I am just looking for a minimal example
Probably some minimal example with DynamicSupervisor might look like
defmodule Recorder do
use GenServer
def start_link(args) do
id = Map.get(args, :id)
GenServer.start_link(__MODULE__, args, name: id)
end
def init(state) do
schedule_fetch_call()
{:ok, state}
end
def handle_info(:jpeg_fetch, state) do
# start worker under dynamic supervisor
DynamicSupervisor.start_child(
Recorder.ImageProcessorSupervisor,
{Recorder.ImageProcessorWorker, state.url}
)
schedule_fetch_call()
{:noreply, Map.put(state, :run, true)}
end
defp schedule_fetch_call do
Process.send_after(self(), :jpeg_fetch, 1000)
end
end
defmodule Recorder.ImageProcessorWorker do
# We use restart: :transient because we don't want
# GenServer to be restarted after normal stop
# see more https://hexdocs.pm/elixir/Supervisor.html#module-restart-values-restart
use GenServer, restart: :transient
def start_link(url) do
GenServer.start_link(__MODULE__, url)
end
def init(url) do
send(self(), :fetch_and_process)
{:ok, url}
end
def handle_info(:fetch_and_process, url) do
# the body of your spawn
IO.inspect("I am being called")
IO.inspect(DateTime.utc_now())
result = Fincher.request(:get, url) |> IO.inspect()
case result do
{:error, %Mint.TransportError{reason: :closed}} ->
# retry
send(self(), :fetch_and_process)
{:noreply, url}
{:ok, response} ->
# do something with the response...
# and stop worker normally
{:stop, :normal, url}
end
end
end
With each second it spans new Recorder.ImageProcessorWorker
that immediately sends to itself :fetch_and_process
(see the only handle_info
callback).
That callback is either successfully finishes its work and terminates the Worker by responding {:stop, :normal}
or retries. (see possible return values)
And in application.ex
don’t forget to register the DynamicSupervisor
children =
[
...
{DynamicSupervisor, strategy: :one_for_one, name: Recorder.ImageProcessorSupervisor}
] ++ get_children()