Skip to content

Instantly share code, notes, and snippets.

@monpetit
Created August 29, 2018 06:28
Show Gist options
  • Save monpetit/770de22164f8590b6a46997df4415b71 to your computer and use it in GitHub Desktop.
Save monpetit/770de22164f8590b6a46997df4415b71 to your computer and use it in GitHub Desktop.
Elixir Periodic Timer with Callback
defmodule PeriodicTimer do
use GenServer
@init_state %{
name: __MODULE__,
count: 0,
run: false,
interval: 1_000,
task: nil,
task_args: []
}
### PUBLIC API
def start_link(name \\ __MODULE__) do
GenServer.start_link(__MODULE__, %{@init_state | name: name}, name: name)
end
def stop!(name \\ __MODULE__) do
GenServer.cast(name, :stop)
end
def run!(name \\ __MODULE__), do: resume!(name)
def resume!(name \\ __MODULE__) do
GenServer.cast(name, :resume)
end
def flip!(name \\ __MODULE__) do
GenServer.cast(name, :flip)
end
def reset!(name \\ __MODULE__) do
GenServer.cast(name, :reset)
end
def set_interval!(ms), do: set_interval!(__MODULE__, ms)
def set_interval!(name, ms) do
GenServer.cast(name, {:set_interval, ms})
end
def interval(name \\ __MODULE__) do
GenServer.call(name, :interval)
end
def set_task!(func, args), do: set_task!(__MODULE__, func, args)
def set_task!(name, func, args) do
GenServer.cast(name, {:set_task, func, args})
end
def state(name \\ __MODULE__) do
GenServer.call(name, :state)
end
### CALLBACKS
def init(state) do
# schedule_work(state)
{:ok, state}
end
def handle_info(:work, state) do
# do important and periodic stuff
if state.run do
if state.task == nil do
IO.puts("[DEFAULT TASK] (on #{state.name}, count: #{state.count})")
else
apply(state.task, [state | state.task_args])
end
schedule_work(state)
end
new_state = if state.run, do: %{state | count: state.count + 1}, else: state
{:noreply, new_state}
end
def handle_cast(:stop, state) do
{:noreply, %{state | run: false}}
end
def handle_cast(:resume, state) do
new_state = %{state | run: true}
schedule_work(new_state)
{:noreply, new_state}
end
def handle_cast(:flip, state) do
if !state.run, do: schedule_work(state)
{:noreply, %{state | run: !state.run}}
end
def handle_cast(:reset, state) do
{:noreply, %{state | count: 0}}
end
def handle_cast({:set_interval, ms}, state) do
{:noreply, %{state | interval: ms}}
end
def handle_cast({:set_task, func, args}, state) do
{:noreply, %{state | task: func, task_args: args}}
end
def handle_call(:interval, _from, state) do
{:reply, state.interval, state}
end
def handle_call(:state, _from, state) do
{:reply, state, state}
end
defp schedule_work(state) do
Process.send_after(self(), :work, state.interval)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment