My app’s flow is as follows. Step 1: Workers under Elixir.AppName.MQTT.Supervisor receive some message. Step 2: This message is sent to Elixir.AppName.Server Step 3:Elixir.AppName.Server starts a worker dynamically under Elixir.AppName.on.Supervisor. Step 4: The worker receives the message and acts accordingly
Let us call the worker, which is a GenServer, WORKER
My problem is that every time I have to perform some task in WORKERs I end up using send self(), message and having a corresponding handle_info in the WORKER.
I feel there is some issue with my current approach as I cannot utilize functions like GenServer.call or GenServer.cast
How should I remodel the application so that it makes use of other GenServer functions and callbacks?
I want to use call mainly because the worker is doing some CRUD operation in DB. I want to block the worker until the task is done.
By API side you mean something that a client(user or application) can use, right?
No intra-server calls have been planned.
Code structure is as follows
AppName.Server
defmodule AppName.Server do
use GenServer
def start_link do
GenServer.start_link/3
end
def init/1 do
send self(), :start_supervisors
{:ok, state}
end
def handle_info/2 do
# :start_supervisors is the message being handled
child_spec = %{...}
Supervisor.start_child(AppName.Supervisor, child_spec)
{:noreply, state}
end
end
AppName.on.Worker
defmodule AppName.on.Worker do
use GenServer
def start_link do
# receives the message as argument
GenServer.start_link/3
end
def init/1 do
send self(), {:check_args, message_from_mqtt_as_map}
{:ok, state}
end
def handle_info({:check_args, message_from_mqtt_as_map}, state) do
case message_from_mqtt_as_map["action"] do
:create ->
do_create(message_from_mqtt_as_map)
send self(), :some_task
:remove ->
do_remove(message_from_mqtt_as_map)
send self(), :some_other_task
:update ->
do_update(message_from_mqtt_as_map)
send self(), :yet_some_other_task
end
{:noreply, state}
end
def handle_info/2 do
# other handle infos for :some_task, :some_other_task, :yet_some_other_task
end
# helper functions for the task
end
# Maybe there is a typo in your module name :slight_smile:
defmodule AppName.on.Worker do
use GenServer
# THIS IS API
def start_link do
# receives the message as argument
GenServer.start_link/3
end
def some_task, do: GenServer.call ...
# THIS IS SERVER SIDE
def init/1 do
send self(), {:check_args, message_from_mqtt_as_map}
{:ok, state}
end
# Wherever You need it...
def handle_call(:some_task, _from, _state) do
perform_some_task()
end
def handle_info({:check_args, message_from_mqtt_as_map}, state) do
case message_from_mqtt_as_map["action"] do
:create ->
do_create(message_from_mqtt_as_map)
perform_some_task()
...
end
{:noreply, state}
end
# helper functions for the task
defp perform_some_task, do: ...
end