Current section
Files
Jump to
Current section
Files
lib/grains/debug_timer.ex
defmodule Grains.DebugTimer do
@moduledoc """
Debug version of `Grains.Timer`.
To replace the normal Timer with this, start you bread like this:
```
recipe = Recipe.new(:Periodic, %{
Source => Grains.periodic(Sink, 10, %{with_timestamps: true}),
})
grains = Grains.new(%{
Source => {Source, %{}, []},
Sink => {Sink, %{}, []},
Source.Timer.Sink => {Grains.DebugTimer, [], []}
})
{:ok, bread} = Grains.Supervisor.start_link(recipe, grains, id: Test)
debug_timer = Grains.get_name(bread, Source.Timer.Sink)
send(debug_timer, :tick)
```
## With Timestamps
Similarly to `Grains.Timer`, the debug timer accepts an option `with_timestamps`. If set to
true, the `:tick` must include a timestamp, which is then used when forwarding the received
message downstream. If `with_timestamps` is not set, the `:tick` must not include a timestamp,
and the message is forwarded as-is.
## With Tags
The debug timer also accepts an option `with_tag`. If set to an atom, the timer will use
`pull_with_tag` instead of `pull`.
"""
use Grains.GenGrain
alias Grains.Timer
defdelegate name(left, grain), to: Timer
defmodule State do
defstruct timestamp: nil, with_timestamps: false, with_tag: false
end
def init(opts) do
state = struct!(State, Map.take(opts, %State{} |> Map.keys()))
{:ok, state}
end
def handle_info(:tick, state) do
{:noreply, tick(state)}
end
def handle_info({:tick, ts}, state) do
{:noreply, tick(state, ts)}
end
def handle_push(msg, _from, state) do
if state.with_timestamps do
now = state.timestamp
:ok = push({now, msg})
else
push(msg)
end
{:noreply, state}
end
def handle_pull(_from, state) do
pull()
{:noreply, state}
end
def handle_pull(_from, tag, state) do
pull_with_tag(tag)
{:noreply, state}
end
defp tick(state = %State{}, ts \\ nil) do
if state.with_tag != false do
pull_with_tag(state.with_tag)
else
pull()
end
if state.with_timestamps do
%State{state | timestamp: ts}
else
state
end
end
end