Current section

Files

Jump to
pixie lib timeouts.ex
Raw

lib/timeouts.ex

defmodule Pixie.Timeouts do
defstruct timer_ref: nil, module: nil, function: nil, args: []
use GenServer
alias Pixie.Timeouts, as: Timeout
@default_timeout 5
def start_link do
GenServer.start_link __MODULE__, initial_state, name: __MODULE__
end
def add(timeout_id, module, function, args) do
add timeout_id, @default_timeout, module, function, args
end
def add timeout_id, timeout_ttl, module, function, args do
GenServer.cast __MODULE__, {:add_timeout, timeout_id, timeout_ttl, module, function, args}
end
def remove timeout_id do
GenServer.cast __MODULE__, {:remove_timeout, timeout_id}
end
def expire timeout_id do
GenServer.cast __MODULE__, {:expire, timeout_id}
end
def handle_cast {:add_timeout, timeout_id, timeout_ttl, mod, fun, args}, state do
timeout = Map.get state, timeout_id, %Timeout{}
cancel timeout
{:ok, tref} = :timer.apply_after timeout_ttl * 1000, __MODULE__, :expire, [timeout_id]
timeout = %{timeout |
timer_ref: tref,
module: mod,
function: fun,
args: args
}
state = Map.put state, timeout_id, timeout
{:noreply, state}
end
def handle_cast {:remove_timeout, timeout_id}, state do
timeout = Map.get state, timeout_id, %Timeout{}
cancel timeout
state = Map.delete state, timeout_id
{:noreply, state}
end
def handle_cast {:expire, timeout_id}, state do
if Map.has_key? state, timeout_id do
%{module: mod, function: fun, args: args} = Map.get state, timeout_id
Task.async mod, fun, args
end
state = Map.delete state, timeout_id
{:noreply, state}
end
defp initial_state do
%{}
end
defp cancel(%Timeout{timer_ref: tref}) when not is_nil(tref) do
:timer.cancel(tref)
end
defp cancel(_), do: nil
end