Elixir async and state management
- Use a
Taskif you want to perform a one-off computation or query asynchronously. - Use an
Agentif you just need a simple process to keep the state. - Use a
GenServerif you need a long-running server process that store states and performs work concurrently. - Use a dedicated
GenServerprocess if you need to serialize access to a shared resource or service used by many concurrent processes. - Use a
GenServerprocess if you need to schedule background work to run on a periodic interval. - You can start with one and migrate to another later, like from
AgenttoGenServer
GenServer callback functions
handle_call(message, from, state)
You want synchronous requests sent by the client. So the client is waiting for an immediate answer - like an ack answer - with the new state.
from is usually ignored. It's format is {pid, tag}.
The return is typically {:reply, reply, new_state}.
handle_cast(message, state)
Handles asynchronous requests sent by the client. The client isn't waiting an acknowledgment.
The return is typically {:noreply, new_state}.
handle_info(message, state)
Handles all other requests. Useful to handle unknown messages as informational actions.
The return is typically {:noreply, state}.
init(args)
When GenServer.start(__MODULE__, [], name: @process_name) is called, [] is the initial state that will the init function will receive.
You can use to customize the initial state passed by the caller.
terminate(reason, state)
A handle_call or handle_cast function might return {:stop, reason, new_state}.
terminate handles the process exit routines, like saving the state and closing files.
Debugging and Tracing
Check the current state
iex> :sys.get_state(pid)
%HttpServer.PledgeServer.State{cache_size: 5, pledges: [{"rodrigo", 15}, {"margot", 25}]}
Trace changes
iex> :sys.trace(pid, true)
:ok
iex> HttpServer.PledgeServer.create_pledge("moe", 20)
*DBG* pledge_server got call {create_pledge,<<"moe">>,20} from <0.152.0>
Full status
:sys.get_status(pid)