在我的应用程序中,所有记录的用户都由一个GenServer
表示,我称之为UserAgent
,它基本上将每个用户的状态保存在内存中。所有这些进程都在集群中注册在一个基于Horde的分布式注册表中,该注册表具有唯一的ID。每当用户执行某个操作时,客户端应用程序都会将要执行的操作与user_id
一起发送。在服务器端,控制器检查参数(强制、可选、语法等(,并最终调用UserAgent.the_action(user_id, other_params)
。the_action(...)
函数只是向服务器发送一条消息,其中包含要执行的操作:GenServer.call(via_tuple(id), {:the_action, params})
。
在某些情况下,user_id
引用的UserAgent
不再存在,例如,因为用户已处于非活动状态一段时间,进程已被清除(sesion已过期(,或者因为此时无法访问集群的某些部分(目前是虚构的用例(。在这些情况下,调用GenServer.call(via_tuple(id), {:the_action, params})
会导致下面的错误,该错误还会使HTTP端点进程(下面的#PID<0.1359.0>
(崩溃,进而导致500
HTTP错误(dump
API调用会出于调试目的转储进程的状态(:
[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
我只是不知道如何拦截这个错误。实际上,我最终在UserAgent
的客户端部分调用Horde.Registry.lookup(App.UserAgent.via_tuple(user_id))
,然后调用GenServer.call() with the returned
pid,或者如果找不到进程,则向控制器返回错误。
我想知道是否有更好的方法。
这就是GenServer.call/3
如何处理elixir中的错误。尽管如此,它还是调用whereis/1
,所以您可以自己调用whereis/1
,或者复制我链接的代码中的逻辑,或者使用Kernel.SpecialForms.try/1
到catch
作为异常。