Rum*_*ilz 6 erlang global gen-server
我想在erlang集群中启动一个唯一的全局注册gen_server进程.如果进程停止或运行它的节点发生故障,则将在其他节点之一上启动该进程.
该过程是主管的一部分.问题是在第二个节点上启动管理程序失败,因为gen_server已在运行并从第一个节点全局注册.
{ok, Pid}已经运行的进程而不是启动新的gen_server实例?
global:trans()在gen_server的start_link函数中使用某种东西吗?
start_link() ->
global:trans({?MODULE, ?MODULE}, fun() ->
case gen_server:start_link({global, ?MODULE}, ?MODULE, [], []) of
{ok, Pid} ->
{ok, Pid};
{error, {already_started, Pid}} ->
link(Pid),
{ok, Pid};
Else -> Else
end
end).
如果您返回{ok,Pid}的内容但未链接到该内容,则会混淆依赖返回值的主管。如果您不想让主管使用它作为start_link函数,则可以摆脱它。
您的方法似乎应该可行,因为如果全局实例死亡,则每个节点都将尝试启动一个新实例。您可能会发现需要增加MaxR主管设置中的值,因为每次集群成员更改时都会收到过程消息。
我过去创建全局单例的一种方法是在所有节点上运行该过程,但让其中一个(赢得全局注册竞赛的一个)作为主节点。其他进程监视主服务器,当主服务器退出时,尝试成为主服务器。(再说一次,如果他们没有赢得注册比赛,那么他们会监视赢得比赛的pid)。如果这样做,则必须自己处理全局名称注册(即,不使用该gen_server:start({global, ...功能),因为您希望该过程开始(无论它是否赢得注册),每种情况下的行为都将有所不同。
该过程本身必须更加复杂(必须同时在主模式和非主模式下运行),但是它可以快速稳定并且不会因管理员启动尝试而产生大量日志垃圾邮件。
我的方法通常需要经过几轮修订才能解决一些棘手的问题,但是在我看来,这比编写OTP分布式应用程序要麻烦得多。与分布式应用程序相比,此方法还有另一个优势,因为您不必静态配置集群中涉及的节点列表-任何节点都可以作为运行流程主副本的候选对象。您的方法具有相同的属性。