Maxximiliann
Supervisors: Need help making heads or tails of a cryptic handle_call error
defmodule Supervisor.Main do
use Supervisor
def start_link(_args) do
Supervisor.start_link(__MODULE__, name: __MODULE__)
end
def init(_) do
Process.flag(:trap_exit, true)
children = [
PyOperatorSupervisor,
Server.SomeMonitor
]
Supervisor.init(children, strategy: :one_for_one)
end
end
defmodule PyOperatorSupervisor do
use Supervisor
@timeout 60_000
def start_link(_) do
Supervisor.start_link(__MODULE__, [], name: __MODULE__)
end
@impl true
def init(_) do
Process.flag(:trap_exit, true)
children = [
:poolboy.child_spec(:py_pool,
name: {:local, :py_pool},
worker_module: Server.PyOperator,
size: 10,
max_overflow: 20
)
]
Supervisor.init(children, strategy: :one_for_one)
end
def handle_call(foo, from, state) do
task = LogBook.testing({:handle_call, arg1: foo, from: from, state: state}, __MODULE__, 28)
{:reply, task, state}
end
def launch({data, py_module, py_lambda}) do
:poolboy.transaction(
:py_pool,
fn pid ->
GenServer.call(pid, {data, py_module, py_lambda}, @timeout)
end,
@timeout
)
end
end
defmodule Server.PyOperator do
use GenServer
use Export.Python
def start_link(_) do
GenServer.start_link(__MODULE__, %{})
end
@impl true
def init(state) do
Process.flag(:trap_exit, true)
priv_path = Path.join(:code.priv_dir(:foo), "python")
{:ok, py} = Python.start_link(python_path: priv_path)
{:ok, Map.put(state, :py, py)}
end
@impl true
def handle_call({args, py_module, py_lambda}, _from, %{py: py} = state) do
report = Python.call(py, py_module, py_lambda, [args])
{:ok, :message_logged} = LogBook.main(report, __MODULE__, 21, :quiet)
{:reply, report, state}
end
@impl true
def handle_info({:EXIT, _, :normal}, state), do: {:noreply, state}
@impl true
def handle_info({:DOWN, _, :process, _, :normal}, state), do: {:noreply, state}
@impl true
def terminate(_reason, %{py: py}) do
Python.stop(py)
:ok
end
end
defmodule Server.SomeMonitor do
use GenServer
@timeout 5_000
def start_link(_) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
@impl true
def init(state) do
Process.flag(:trap_exit, true)
Process.send(self(), :kickoff, state)
{:ok, state}
end
@impl true
def handle_info(
:kickoff,
state
) do
DoWork.launch()
Process.send(self(), :update, state)
{:noreply, state}
end
@impl true
def handle_info(:update, state) do
timeout_reference = Process.send_after(self(), :job_timeout, @timeout)
task =
Task.Supervisor.async(
PyOperatorSupervisor,
fn -> PyOperatorSupervisor.launch({[], "foo", "bar"}) end
)
result = Task.await(task, 10_000)
Process.cancel_timer(timeout_reference)
case result do
{:ok, some_response} ->
LogBook.testing(some_response, __MODULE__, 46)
{:ok, _} = Baz.main(some_response)
Process.send(self(), :update, state)
{:noreply, state}
{:error, reason} ->
LogBook.main(
{:glitch, critical_error: reason, state: state},
__MODULE__,
55,
:error
)
{:stop, reason, state}
end
{:noreply, state}
end
@impl true
def handle_info(:job_timeout, state) do
LogBook.main(
"Still waiting for stuff to come in. Elapsed time: #{@timeout / 1000} second(s).",
__MODULE__,
70,
:warning
)
{:noreply, state}
end
@impl true
def handle_info(critical_error, state), do: {:stop, critical_error, state}
@impl true
def terminate(critical_error, state),
do: LogBook.main({critical_error, state}, __MODULE__, 82, :error)
end
Error Message:
%{size: 2, type: 'Tuple', value: {{{:function_clause, [{:supervisor, :handle_call, [{:start_task, [{:nonode@nohost, Server.SomeMonitor, #PID<0.441.0>}, :monitor], :temporary, nil}, {#PID<0.441.0>, #Reference<0.1421632187.1679294465.116665>}, {:state, {:local, PyOperatorSupervisor}, :one_for_one, {[:py_pool], %{py_pool: {:child, #PID<0.418.0>, :py_pool, {:poolboy, :start_link, [[name: {:local, :py_pool}, worker_module: Server.PyOperator, size: 10, max_overflow: 20], []]}, :permanent, false, 5000, :worker, [:poolboy]}}}, :undefined, 3, 5, [], 0, :never, PyOperatorSupervisor, []}], [file: 'supervisor.erl', line: 435]}, {:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 1146]}, {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 1175]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 240]}]}, {GenServer, :call, [PyOperatorSupervisor, {:start_task, [{:nonode@nohost, Server.SomeMonitor, #PID<0.441.0>}, :monitor], :temporary, nil}, :infinity]}}, []}}
What is this error trying to communicate and how is the underlying issue resolved?
Marked As Solved
Maxximiliann
My goof was not using a different name for the Task Supervisor. Here’s what the working code looks like:
defmodule MyApp.Application do
require Logger
use Application
def start(_type, _args) do
:logger.add_handlers(:myApp)
Print.text("Initiating MyApp", __MODULE__, 8)
children = [
MyAppDB.Repo,
Supervisor.Main
]
options = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, options)
end
end
defmodule Supervisor.Main do
use Supervisor
def start_link(_args) do
Supervisor.start_link(__MODULE__, name: __MODULE__)
end
def init(_) do
Process.flag(:trap_exit, true)
children = [
{Task.Supervisor, name: TasksSupervisor},
Server.SomeMonitor
]
Supervisor.init(children, strategy: :one_for_one)
end
end
defmodule Server.SomeMonitor do
use GenServer
...
def handle_info(:update, state) do
...
task =
Task.Supervisor.async(
TasksSupervisor,
fn -> PyOperatorSupervisor.launch({[], "foo", "bar"}) end
)
...
{:noreply, state}
end
...
end
Thanks again for your all your help! ![]()
Also Liked
josevalim
My suspicion is that is you are calling Task.Supervisor.start_child or similar on a regular supervisor (which is not a Task.Supervisor).
josevalim
Exactly.
al2o3cr
I’m not sure why the Erlang → Elixir error-translation isn’t handling this, but I believe this means that something is trying to GenServer.call with :start_task at a process that doesn’t have a matching handle_call.
I’d start by looking for :start_task in your code, as it doesn’t appear anywhere in what’s posted. ![]()
Maxximiliann
Thanks for your input ![]()
task =
Task.Supervisor.async(
PyOperatorSupervisor,
fn -> PyOperatorSupervisor.launch({[], "foo", "bar"}) end
)
It seems you’re suggesting that in the code above PyOperatorSupervisor should be a Task.Supervisor. Am I on the right track or no?
josevalim
You most likely have application.ex file (if not, please say so). In there, you define the supervision tree of your application. You should list Supervisor.Main main as a child there.
In other words, no supervisor start dynamically. You need to start them all the way down from your application.ex start/2 definition.







