Skip to content

Instantly share code, notes, and snippets.

@LukeWood
Last active June 8, 2019 23:19
Show Gist options
  • Save LukeWood/7fd2c49ea452ed8f204fb23500dac924 to your computer and use it in GitHub Desktop.
Save LukeWood/7fd2c49ea452ed8f204fb23500dac924 to your computer and use it in GitHub Desktop.
defmodule Stopwatch.Client do
def subscribe(pid, func) do
GenServer.cast(pid, {:subscribe, func})
end
end
{:ok, pid} = Stopwatch.Supervisor.new_stopwatch()
Stopwatch.Client.subscribe(pid, fn elapsed_millis -> IO.inspect(elapsed_millis) end)
# > prints time elapsed every interval
defmodule Stopwatch.Server do
use GenServer
@tick_interval 100
def start_link() do
Genserver.start(__MODULE__, %{notify_callbacks: [], start_time: os.system_time(:millisecond)})
end
def init(time) do
schedule_tick(self())
{:ok, state}
end
# You can listen for these events from other modules after starting a stopwatch
def handle_cast({:subscribe, func}, state) do
{:noreply, Map.put(state, :notify_callbacks, [func | notify_callbacks])}
end
# Call all functions in notify_callbacks with the elapsed amount of time
def handle_info(:tick, state = %{notify_callbacks: notify_callbacks, start_time: start_time) do
elapsed_time = os.system_time(:millisecond)-start_time
Enum.map(notify_callbacks, fn func -> func.(elapsed_time) end)
schedule_tick(self())
{:noreply, state}
end
def schedule_tick(pid) do
Process.send_after(pid, :tick, @tick_interval)
end
end
defmodule Stopwatch.Supervisor do
use DynamicSupervisor
def start_link() do
DynamicSupervisor.start_link(__MODULE__, :ok, name: __MODULE__)
end
def new_stopwatch() do
spec = {Stopwatch.Server, []}
DynamicSupervisor.start_child(__MODULE__, spec)
end
def init(:ok) do
DynamicSupervisor.init(
strategy: :one_for_one,
extra_arguments: []
)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment