When I have many access in Phoenix application,
GenServer mailbox is stack, and entire process finish late.
code is like this below.
defmodule Hoge do
def exec(account_code, x1), do: GenServer.cast(pid, {:exec, arg})
@impl true
def handle_cast({:exec, arg1}, state) do
// something process
{:noreply, state}
end
end
My understanding is that GenServer.cast is asynchronous and accumulates the jobs that defined in handle_call in the mailbox, but it processes those accumulated jobs one by one.
However, I want to process those jobs in parallel.
What I want to do
I want to proccess entire job quickly.
So I am thinking I chage it using Task.async so that I can process multiple jobs.
It worked, but I wonder this is right.
In this case, handle_call returns {:noreply, state} before process finish, because Task is asynchronous.
defmodule Hoge do
def exec(account_code, x1), do: GenServer.cast(pid, {:exec, arg})
@impl true
def handle_cast({:exec, arg1}, state) do
Task.async(fn ->
// something process
end)
{:noreply, state}
end
end
It would be very glad if anyone have ideas and tell me that🙏
If you are using async tasks, you must await a reply as they are always sent. If you are not expecting a reply, consider using Task.start_link/1 as detailed below.
So if we want to use Task to process something asynchronously and wait for the result, we can return as state it’s awaited result
def handle_cast({:exec, arg1}, state) do
task = Task.async(fn ->
// something process
end)
{:noreply, Task.await(task)}
end
We return as the gen servers state the result of the task, but you might not want that. You should use await though to wait for the task
As a general rule, if you find everything in your system standing in a line for one process you should consider a different design that avoids the problem.
If the results of something process don’t affect the value of state at all, the code likely shouldn’t be in a GenServer. The “when (not) to use a GenServer” section in the docs explains further.
As long as I can process in paralell, I don’t have to use Task necessarily.
In this case, it seems like I better not to use Task.
It would be glad if you have any ideas and tell me that beside beside Task.
This process is designed to handle webhooks from other applications. Since I need to return a 200 response immediately and process the request later, I am sending the task asynchronously to a GenServer.
There’s two main ways I have seen this solved. One is with a durable queue, for example Oban. Your controller queues a job, and returns the 200 response. Then the job framework executes it asynchronously. The other approach is to use a DynamicSupervisor in your supervision tree and your controller starts a Task within that supervisor, then returns the 200. This approach is most similar to what you described, but avoids the bottleneck of one GenServer.