Packages

a simple, generic behaviour for doing stuff on some interval

Current section

Files

Jump to
gen_poller lib gen_poller.ex
Raw

lib/gen_poller.ex

defmodule GenPoller do
@moduledoc """
A behaviour for creating a simple looping `GenServer`. `GenPoller` is backed by the `GenServer`
module so it offers all of the same callbacks that `GenServer` does. This allows the process to
respond to interleaved messages while polling. The `poll_sleep` arg must be provided.
defmodule MyModule do
use GenPoller
# Optionally wrap `GenPoller.start_link`
def start_link do
GenPoller.start_link(__MODULE__, poll_sleep: 1000)
end
# Optionally override `init`
def init(state) do
send(self(), :do_loop)
{:ok, state}
end
# The `handle_tick` callback must be implemented
def handle_tick(state) do
{:continue, state}
end
end
The `handle_tick/1` callback must be implemented. It should return any of the following tuples:
* `{:continue, state}` will cause the loop to resume in `state.poll_sleep`
* `{:pause, state}` will cause the loop to stop until `start_loop` is called again
* Any tuple that is a valid return value for `handle_info`
"""
@callback handle_tick(state :: any) :: new_state :: any
defdelegate start_link(mod, args), to: GenServer
defdelegate start_link(mod, args, opts), to: GenServer
defdelegate start(mod, args), to: GenServer
defdelegate start(mod, args, opts), to: GenServer
@doc """
Resumes or starts the poll loop for the current process.
"""
def start_loop do
send(self(), :do_loop)
end
@doc """
Like `start_loop` but resumes the poll loop after `ms` milliseconds
"""
def start_loop_in(ms) do
Process.send_after(self(), :do_loop, ms)
end
defmacro __using__(_) do
quote do
use GenServer
@behaviour GenPoller
def init(state) do
GenPoller.start_loop
{:ok, state}
end
defoverridable [init: 1]
def handle_info(:do_loop, state) do
case handle_tick(state) do
{:continue, state} ->
Process.send_after(self(), :do_loop, state[:poll_sleep])
{:noreply, state}
{:pause, state} ->
{:noreply, state}
res -> res
end
end
end
end
end