To create a custom consumer supervisor, use the ConsumerSupervisor module. This provides the necessary boilerplate and implements the GenStage behaviour.
Implementation Steps
use ConsumerSupervisor in your module.- Implement
start_link/1 to call ConsumerSupervisor.start_link/3. - Implement
init/1. The init/1 callback must return {:ok, children, opts} or :ignore.
Child Specification Requirements
When defining children in init/1, ensure the :restart option is set to :temporary or :transient. Using :permanent will result in an error.
Example
defmodule MyConsumer do
use ConsumerSupervisor
def start_link(arg) do
ConsumerSupervisor.start_link(__MODULE__, arg)
end
def init(_arg) do
# Define the template for children to be spawned per event
children = [%{id: Worker, start: {Worker, :start_link, []}, restart: :transient}]
# Configure subscription and strategy
opts = [strategy: :one_for_one, subscribe_to: [{Producer, max_demand: 20, min_demand: 10}]]
ConsumerSupervisor.init(children, opts)
end
end
defmodule Consumer do
use ConsumerSupervisor
def start_link(arg) do
ConsumerSupervisor.start_link(__MODULE__, arg)
end
def init(_arg) do
# Note: By default the restart for a child is set to :permanent
# which is not supported in ConsumerSupervisor. You need to explicitly
# set the :restart option either to :temporary or :transient.
children = [%{id: Printer, start: {Printer, :start_link, []}, restart: :transient}]
opts = [strategy: :one_for_one, subscribe_to: [{Producer, max_demand: 50}]]
ConsumerSupervisor.init(children, opts)
end
end
Then in the `Printer` module:
defmodule Printer do
def start_link(event) do
# Note: this function must return the format of `{:ok, pid}` and like
# all children started by a Supervisor, the process must be linked
# back to the supervisor (if you use `Task.start_link/1` then both
# requirements are met automatically)
Task.start_link(fn ->
IO.inspect({self(), event})
end)
end
end