2

我想知道当它们与密钥相关联时如何处理临时 gen_servers 状态的保存。

要将键与进程关联,我使用了一个名为 pidstore 的进程。Pidstore 最终启动进程。我给 pidstore 一个 Key 和一个 M,F,A,它在全局中查找密钥,然后如果找到则返回 pid 或应用 MFA(必须返回 {ok, Pid}),用密钥注册 Pid全局并返回 Pid。

我可能有许多不活动的 gen_servers,它们的状态可能很大。因此,我设置了 handle_info 回调以将状态保存在我的数据库中,然后停止该过程。gen_servers 在他们的主管中被认为是暂时的,所以它们不会重新启动,直到有东西再次需要它们。

问题从这里开始:如果我在代表 {car, 23} 的进程中的 handle_info 的保存步骤期间用它的键调用一个进程,比如 {car, 23},我会按预期取回 pid,因为过程正在保存且未完成。所以我会用 gen_server:call 调用我的进程,但我永远不会有响应(并达到默认的 5 秒超时),因为进程正在停止。(问题一)

为了解决这个问题,进程可以从全局注销自己,然后保存它的状态,然后停止。但是,如果我在注销后但在保存完成之前需要它,我将加载一个新进程,该进程可能会在数据库中加载未更新的值。(问题 B)

为了再次解决这个问题,我可以确保数据库中的加载和保存被排队并且不能并发。这可能是一个瓶颈。(问题 C)

我正在考虑另一种解决方案:我的进程在保存之前可以告诉 pidstore 他们很忙。pidstore 将保留一个繁忙进程的列表,并对这些键的任何需求做出“忙碌”响应。保存完成后,进程将告诉 pidstore no_more_busy 并在询问密钥时启动新进程。(即使旧的过程没有完成,它已经完成保存,所以它可以花时间独自死去)。

这对我来说似乎有点混乱,但是尝试多次从密钥中获取 Pid 感觉更简单,而不是包装对 gen_server 的每次调用以处理可能的超时。(当流程完成但仍在全球注册时)。

我对所有这些半问题和半解决方案有点困惑。您在这种情况下使用的设计是什么,或者我该如何避免这种情况?

我希望我的信息清晰易读,也请告诉我英文错误。

谢谢你

4

2 回答 2

1

也许您想在gen_server:call. 这将阻止其他呼叫在您写入 DB 时进入。

一般来说,听起来您已经创建了一个进程寄存器。如果您想在本地注册,您可能想查看 gproc ( https://github.com/uwiger/gproc ),它在这方面做得很好。使用 gproc,您可以完全按照上面描述的方式进行操作,使用密钥注册进程。init如果您在函数中注册 gproc 并在写入 DB 时取消注册,也许就足够了。terminate您也可以在函数中写入 DB 。

于 2012-04-27T18:00:55.350 回答
0

现在我决定坚持 erlang “让它崩溃”的哲学。如果一个进程在关闭时收到消息,这些消息将不会得到答复,并将触发 gen_server:call/* 超时。

我认为在正确的地方处理这个超时会很无聊,我现在还没有决定在哪里,但这是特定于我的应用程序的,所以在这里没有意义。

于 2012-05-02T16:06:45.473 回答