Skip to content

Commit

Permalink
Refactor Guardian.DB.Sweeper
Browse files Browse the repository at this point in the history
Moved the Sweeper functionality out from inside the Token
namespace/folder. Also simplified the code by combining the two separate
but unnecessary modules. Updated and added test coverage.
  • Loading branch information
doomspork committed May 16, 2021
1 parent 27be739 commit bff7f9d
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 122 deletions.
70 changes: 70 additions & 0 deletions lib/guardian/db/sweeper.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
defmodule Guardian.DB.Sweeper do
@moduledoc """
A GenServer that periodically checks for, and expires, tokens from storage.
To leverage the automated Sweeper functionality update your project's Application
file to include the following child in your supervision tree:
## Example
worker(Guardian.DB.Sweeper, [interval: 60])
"""
use GenServer

alias Guardian.DB.Token

@sixty_minutes 60 * 60 * 1000

def start_link(opts) do
interval = Keyword.get(opts, :interval, @sixty_minutes)
GenServer.start_link(__MODULE__, [interval: interval], name: __MODULE__)
end

@impl true
def init(state) do
{:ok, schedule(state)}
end

@impl true
def handle_cast(:reset_timer, state) do
{:noreply, schedule(state)}
end

@impl true
def handle_cast(:sweep, state) do
Token.purge_expired_tokens()
{:noreply, schedule(state)}
end

@impl true
def handle_info(:sweep, state) do
Token.purge_expired_tokens()
{:noreply, schedule(state)}
end

def handle_info(_, state), do: {:noreply, state}

@doc """
Manually trigger a database purge of expired tokens. Also resets the current
scheduled work.
"""
def purge do
GenServer.cast(__MODULE__, :sweep)
end

@doc """
Reset the purge timer.
"""
def reset_timer do
GenServer.cast(__MODULE__, :reset_timer)
end

defp schedule(opts) do
if timer = Keyword.get(opts, :timer), do: Process.cancel_timer(timer)

interval = Keyword.get(opts, :interval)
timer = Process.send_after(self(), :sweep, interval)

[interval: interval, timer: timer]
end
end
44 changes: 0 additions & 44 deletions lib/guardian/db/token/sweeper.ex

This file was deleted.

58 changes: 0 additions & 58 deletions lib/guardian/db/token/sweeper_server.ex

This file was deleted.

55 changes: 35 additions & 20 deletions test/guardian/sweeper_test.exs
Original file line number Diff line number Diff line change
@@ -1,31 +1,46 @@
defmodule Guardian.DB.Token.SweeperTest do
defmodule Guardian.DB.SweeperTest do
use Guardian.DB.TestSupport.CaseTemplate

alias Guardian.DB.Token
alias Guardian.DB.Token.Sweeper
alias Guardian.DB.Sweeper

test "purge stale tokens" do
Token.create(
%{"jti" => "token1", "aud" => "token", "exp" => Guardian.timestamp() + 5000},
"Token 1"
)
describe "purge/0" do
test "purges expired tokens" do
Token.create(
%{"jti" => "token1", "aud" => "token", "exp" => Guardian.timestamp() + 5000},
"Token 1"
)

Token.create(
%{"jti" => "token2", "aud" => "token", "exp" => Guardian.timestamp() - 5000},
"Token 2"
)
Token.create(
%{"jti" => "token2", "aud" => "token", "exp" => Guardian.timestamp() - 5000},
"Token 2"
)

interval = 0
state = %{interval: interval}
new_state = Sweeper.sweep(state)
{:ok, pid} = Sweeper.start_link(interval: 1_000_000_000)
Sweeper.purge()

token1 = get_token("token1")
token2 = get_token("token2")
GenServer.stop(pid)

assert token1 != nil
assert token2 == nil
token1 = get_token("token1")
token2 = get_token("token2")

assert new_state[:timer] != nil
assert_receive :sweep, interval + 10
assert token1 != nil
assert token2 == nil
end
end

describe "reset_timer" do
test "cancels and restarts the existing timer" do
interval = 1_000_000_000
{:ok, pid} = Sweeper.start_link(interval: interval)

[interval: ^interval, timer: timer] = :sys.get_state(pid)

Sweeper.reset_timer()

[interval: _interval, timer: new_timer] = :sys.get_state(pid)

assert timer != new_timer
end
end
end

0 comments on commit bff7f9d

Please sign in to comment.