Reputation: 1339
In my application all logged users are represented by a GenServer
, I call a UserAgent
, which basically keeps in memory the state of each user. All those processes are registered across the cluster in a distributed registry based on Horde with a unique ID. Whenever the user does some action, the client application sends the action to be performed along with the user_id
. On server side, the controller checks the parameters (mandatory, optional, syntax, etc) and eventually calls UserAgent.the_action(user_id, other_params)
. The the_action(...)
function simply sends a message to the server with the action to be performed: GenServer.call(via_tuple(id), {:the_action, params})
.
In some cases, the UserAgent
referenced by user_id
doesn't exist any more, for example because the user had been inactive for some time and the process had been cleaned out (the sesion had expired) or because parts of the cluster are not reachable at that moment (imaginary use case for the moment). In those situations the call GenServer.call(via_tuple(id), {:the_action, params})
results in the error below which also crashes the HTTP endpoint process (#PID<0.1359.0>
below) which in turn results in a 500
HTTP error (the dump
api call, well, dumps the state of a process for debug purposes):
[error] #PID<0.1359.0> running AppWeb.Endpoint (connection #PID<0.1358.0>, stream id 1) terminated
Server: localhost:4001 (http)
Request: GET /api/v1/dump/5f534b99d6ca3fe1ff6d2f78
** (exit) exited in: GenServer.call({:via, Horde.Registry, {App.DReg, "5f534b99d6ca3fe1ff6d2f78"}}, :dump, 5000)
** (EXIT) no process: the process is not alive or there's no process currently associated \
with the given name, possibly because its application isn't started
I just can't figure out how to intercept this error. I actually ended up with calling Horde.Registry.lookup(App.UserAgent.via_tuple(user_id))
in the client part of the UserAgent
and then calling GenServer.call() with the returned
pid` or returning an error to the controller if the process was not found.
I was wondering if there was a better way.
Upvotes: 1
Views: 670
Reputation: 121000
This is how GenServer.call/3
handles errors in elixir. It nevertheless calls whereis/1
, so you might either call whereis/1
yourself or replicate logic from the code I linked or use Kernel.SpecialForms.try/1
to catch
the exception.
Upvotes: 3