Reputation: 2856
I wanna to try to start Agent in Supervisor with one line for test purpose:
iex(1)> {:ok, pid} = Supervisor.start_link([{Agent, [fn -> 42 end, name: :test]}], strategy: :one_for_one)
** (EXIT from #PID<0.115.0>) evaluator process exited with reason: shutdown: failed to start child: Agent
** (EXIT) an exception was raised:
** (FunctionClauseError) no function clause matching in Agent.start_link/2
(elixir) lib/agent.ex:215: Agent.start_link([#Function<20.99386804/0 in :erl_eval.expr/5>, {:name, :test}], [])
(stdlib) supervisor.erl:365: :supervisor.do_start_child/2
(stdlib) supervisor.erl:348: :supervisor.start_children/3
(stdlib) supervisor.erl:314: :supervisor.init_children/2
(stdlib) gen_server.erl:365: :gen_server.init_it/2
(stdlib) gen_server.erl:333: :gen_server.init_it/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Please notice Supervisor.start_link([{Agent, [fn -> 42 end, name: :test]}], strategy: :one_for_one)
, This code throw error to me, Is it problems with syntax?
I am using Elixir 1.5
Upvotes: 1
Views: 1100
Reputation: 10061
The reason this is happening is because the type for Supervisor.start_link/2
is start_link([:supervisor.child_spec | {module, term} | module], options) :: on_start
With how you are passing in data, it looks like you are trying to use {module, term}
. That term
is what will be passed to the first argument for module
's start_link/2
function. So, the equivalent of what you were trying to do is Agent.start_link([fn -> 42 end, name: :test], [])
(you can see this in the error). You are passing everything into the first argument of the function which, in this case, does not allow for taking a list.
You are going to want to use the :supervisor.child_spec
path. Something along the lines of the following should work for you.
import Supervisor.Spec
children = [
worker(Agent, [fn -> 42 end, name: :test])
]
opts = [strategy: :one_for_one]
Supervisor.start_link(children, opts)
EDIT
You just mentioned in a comment that you are using Elixir 1.5.
You are going to want to create a module that wraps the behaviour of an Agent
.
defmodule MyAgent do
use Agent
def add(pid, n) do
Agent.update(pid, fn state -> state + n end)
end
def subtract(pid, n) do
Agent.update(pid, fn state -> state - n end)
end
def start_link(fun, opts) do
Agent.start_link(fun, opts)
end
# This function is important because it is how we know how to pass the various options to the actual start_link function.
def child_spec([fun | rest]) do
%{
id: __MODULE__,
# The fun and rest here are the function we pass in and then the options. Feel free to do this how you want.
start: {__MODULE__, :start_link, [fun, rest]},
restart: :permanent,
shutdown: 5000,
type: :worker
}
end
end
Now calling Supervisor.start_link([{My Agent, [fn -> 42 end, name: :test]}], strategy: :one_for_one)
should return {:ok, pid}
.
Upvotes: 2