-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
Showing
4 changed files
with
105 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |