我想知道如何在与密钥相关联时保存瞬态gen_servers状态。
要将密钥与进程关联,我使用一个名为pidstore的进程。 Pidstore最终启动流程。 我给一个密钥和一个M,F,A给pidstore,它在全局中查找密钥,然后如果找到则返回pid或者应用MFA(必须返回{ok,Pid}),用密钥注册Pid全局并返回Pid。
我可能有许多非活动的gen_servers,状态可能很大。所以,我设置了handle_info回调来保存我的数据库中的状态,然后停止进程。 gen_servers在他们的主管中被认为是瞬态的,因此在需要它们之前不会重新启动它们。
这里开始出现问题:如果我在代表{car,23}的过程中在handle_info的保存步骤中调用一个带有密钥的进程,比如说{car,23},我将按预期收回pid ,因为这个过程是保存而没有完成的。所以我将使用gen_server调用我的进程:call但我永远不会有响应(并且默认为5秒超时)因为进程正在停止。 (问题A)
要解决此问题,该过程可以从全局取消注册,然后保存其状态,然后停止。但是如果我在未注册之后需要它,但在保存完成之前,我将加载一个新进程,此进程可以在数据库中加载未更新的值。 (问题B)
为了再次解决这个问题,我可以确保数据库中的加载和保存入队并且不能并发。这可能是一个瓶颈。 (问题C)
我正在考虑另一种解决方案:我的流程在保存之前可以告诉pidstore他们很忙。 pidstore将保留繁忙进程的列表,并对theese密钥的任何需求做出“忙碌”响应。 保存完成后,进程会告诉pidstore no_more_busy,并在被问到密钥时启动新进程。 (即使旧的过程没有完成,它已经完成了保存,所以它可以花时间单独死亡)。
对我来说这看起来有点乱,但是做几次尝试从键中获取Pid而不是将每次调用都包装到gen_server来处理可能的超时感觉更简单。 (当流程完成但仍在全球注册时)。
我对所有这些半问题和半解决方案感到有些困惑。在这种情况下您使用的设计是什么,或者我如何避免这种情况?
我希望我的信息清晰可辨,请告诉我有关英语错误的信息。
谢谢
答案 0 :(得分:1)
也许你想在gen_server:call
中保存到数据库部分。这样可以防止在您写入数据库时其他调用进入。
通常听起来像是你创建了一个进程寄存器。您可能希望查看gproc(https://github.com/uwiger/gproc),如果您想在本地注册,那么该工作做得非常好。使用gproc,您可以完全按照上面的描述进行操作,使用密钥注册进程。如果您在init
函数中注册gproc并在写入DB时取消注册,那么这样就足够了。您也可以在terminate
函数中写入数据库。
答案 1 :(得分:0)
现在我决定坚持使用erlang«让它崩溃»的理念。如果一个进程在收到消息时收到消息,那么这些消息将无法应答并触发gen_server:call / * timeout。
我觉得在正确的地方处理这个超时是很无聊的,我现在还没有决定在哪里,但这是我的应用所特有的,所以这里没有意义。