Erlang:单身人士的最佳途径

设置:

我想在erlang集群中启动一个独特的全局注册gen_server进程。 如果进程停止或节点正在运行,则该进程将在其他节点之一上启动。

该过程是主管的一部分。 问题在于启动第二个节点上的管理引擎失败,因为gen_server已经在运行并从第一个节点全局注册。

问题(S):

  • 是否可以检查进程是否已经全局注册到gen_server的start_link函数中,并且在这种情况下返回正在运行的进程的{ok, Pid}而不是启动一个新的gen_server实例?
  • 这是否正确?这样一个进程将成为多个主管的一部分,如果一个进程停止,所有其他节点上的所有主管都将尝试重新启动进程。 第一个主管将创建一个新的gen_server进程,其他主管都将再次链接到该进程。
  • 我应该在gen_server的start_link函数中使用某种global:trans()吗?
  • 示例代码:

    
    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).
    
    
    

    将gen_server转变为应用程序并使用分布式应用程序如何?


    如果你返回{ok,Pid}你没有链接的东西会混淆依赖返回值的管理员。 如果你不想要一个主管将它用作start_link函数,你可以避开它。

    您的方法似乎应该起作用,因为如果全局节点死亡,每个节点都会尝试启动一个新的实例。 您可能会发现您需要在管理员设置中增加MaxR值,因为每当群集成员更改时您都会收到处理消息。

    我过去创建全局单例的一种方法是在所有节点上运行该进程,但其中一个(获得全局注册竞赛的人)成为主节点。 其他进程监视主服务器,当主服务器退出时,尝试成为主服务器。 (再次,如果他们没有赢得注册竞赛,那么他们会监控所做的那个)。 如果你这样做,你必须自己处理全局名称注册(即不要使用gen_server:start({global, ... functionality),因为无论它是否赢得注册,您都希望该过程开始,它会只是在每种情况下表现不同。

    这个过程本身必须更加复杂(它必须在主模式和非主模式下运行),但它很快稳定下来,并且不会在管理员启动尝试时产生大量日志垃圾邮件。

    我的方法通常需要进行几轮修改来摆脱角落的情况,但是在我看来,编写OTP分布式应用程序的麻烦比较少。 与分布式应用程序相比,此方法具有另一个优点,即您无需静态配置集群中涉及的节点列表 - 任何节点都可以成为运行进程主副本的候选项。 你的方法有这个相同的属性。

    链接地址: http://www.djcxy.com/p/38217.html

    上一篇: Erlang: Best way for a singleton gen

    下一篇: How to reference previously started processes in an Elixir supervisor