是否可以同时运行不同的Erlang OTP版本?

时间:2017-10-18 02:16:31

标签: ios erlang apple-push-notifications otp

我正在尝试将Apple的voip推送通知添加到我们的应用中。我们的后端提供程序由Erlang的Ejabberd服务器和apns4erl服务器1.0.4编写。

目前,apns4erl 2具有发送voip推送通知的能力。但它需要OTP 19+进行编译,我们的系统在OTP 17.3上运行。

所以我可以知道是否可以同时运行这两个OTP?我无法将OTP升级到19+。新图书馆需要19岁以上。

有没有很好的方法可以满足这个要求,或者我需要将新库移植到旧库中?

谢谢,

埃里克

2 个答案:

答案 0 :(得分:4)

在阅读本文时请记住,您应真正找到更新现有服务的方法,以便及时了解更新的运行时。我只是因为有人认为他们需要以一种无法升级的方式将某个特定模块分叉 - 而这只是一场噩梦。

TL; DR :(但无论如何你应该阅读它)

是的,我刚刚确认您可以通过disterl 连接R17和R20节点并发送消息:

R17节点:

ceverett@changa:/opt/erlang/R17.5/bin$ ./erl -name bar -cookie walnut
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V6.4  (abort with ^G)
(bar@changa.shinden.tsuriai.jp)1> P = spawn(fun Wait() -> receive {From, Message} -> From ! {received, Message}, Wait() end end).
<0.44.0>
(bar@changa.shinden.tsuriai.jp)2> global:register_name(waiter, P).
yes

R20节点:

ceverett@changa:~$ erl -name foo -cookie walnut                                                                                                                                                                                                                              
Erlang/OTP 20 [RELEASE CANDIDATE 2] [erts-9.0] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:10] [hipe] [kernel-poll:false]                                                                                                                                         

Eshell V9.0  (abort with ^G)
(foo@changa.shinden.tsuriai.jp)1> net_kernel:connect('bar@changa.shinden.tsuriai.jp').
true
(foo@changa.shinden.tsuriai.jp)2> global:send(waiter, {self(), "blah blah blah"}).
<7489.44.0>
(foo@changa.shinden.tsuriai.jp)3> flush().
Shell got {received,"blah blah blah"}
ok

请注意,R20节点首先是首先启动,因此这是正在运行的EPMD版本。我不知道这是否重要,我也不知道EP17D是否在R17和R20之间发生了变化。

这是所有未记录的功能。请阅读以下内容,了解 更多面向未来的方法。

连接两个不同版本节点的文档化方法是使用+R运行时标志。我认为这是一个非常不可靠的黑客(正如我上面所说的那样不可靠),除非你先彻底测试它 - 它可能会产生意想不到的副作用,具体取决于所涉及的版本(并且没有告诉我们会发生什么)未来)。但是这是一个实际的运行时标志,它显然存在是有原因的。有关详细信息,请参阅legoscia's answer

讨论

两个版本的Erlang的运行时是否与disterl兼容,在Erlang中编写网络应用程序非常简单。您始终可以通过TCP连接两个不同的东西。

对此的简单解决方案是使用当前版本的Erlang(目前为R20.1)在Erlang中编写一个网络应用程序,该应用程序接收Apple voip推送,并将它们转发到您的主应用程序。

写:

  • R17系统内的单个TCP套接字处理过程。
  • R20中的Apple VOIP推送服务处理程序和与R17 TCP套接字处理程序通信的TCP套接字连接进程。

将系统中的Apple VOIP服务视为应用程序的本机部分。 R17节点中的套接字处理程序是 VOIP服务。确保编写其接口函数时考虑到这一点 - 以后如果您可以将代码迁移到R20,那么您不必担心这个细节,因为它已经被Erlang中的内部协议抽象了。 p>

至于推送更新本身,您可以创建任何类型的协议。

Erlang的external term format在R17和R20之间没有变化,因此您可以通过Apple VOIP侧套接字处理程序(在R20节点上)执行某些操作来在两个节点之间发送本机消息像:

notify_node(Socket, VOIP_Data) ->
    Message = term_to_binary({push, VOIP_Data}),
    ok = gen_tcp:send(Socket, Message),
    log(info, "Message sent").

在接收节点(R17节点)上:

loop(Parent, Debug, State = #s{socket = Socket}) ->
    receive
        {tcp, Socket, Bin} ->
            {push, VOIP_Data} = binary_to_term(Bin, [safe]),
            {ok, NewState} = do_stuff(VOIP_Data, State)
            loop(Parent, Debug, NewState);
        %% Your other stuff
        %% OTP system stuff
    end.

你也可以把R17一边写成gen_server,听:

handle_info({tcp, Socket, Bin}, State = #s{socket = Socket}) ->
    %% whatever

我恰好碰巧在大多数情况下将套接字处理过程视为proc_lib进程而不是gen_servers。但在大多数情况下,这并不重要。

另一种方法是使用二进制文件:

notify_node(Socket, VOIP_Data) ->
    Message = <<"PUSH ", VOIP_Data>>,
    ok = gen_tcp:send(Socket, Message),
    log(info, "Message sent").

在接收节点(R17节点)上:

loop(Parent, Debug, State = #s{socket = Socket}) ->
    receive
        {tcp, Socket, <<"PUSH ", VOIP_Data/binary>>} ->
            {ok, NewState} = do_stuff(VOIP_Data, State)
            loop(Parent, Debug, NewState);
        %% Your other stuff
        %% OTP system stuff
    end.

这实际上取决于VOIP_Data的性质。如果它本身就是二进制文件并且R20 Apple推送服务应该只是传递它而不检查它,那么原始二进制方法很容易。如果R20方面要解释消息并将其转换为自己的Erlang消息,那么您可以使用binary_to_term/1 / term_to_binary/2更好地 形式。

答案 1 :(得分:3)

zxq9's answer涵盖了针对这种特殊情况需要了解的所有内容。我只想提一下+R标志:

  

+R ReleaseNumber
  设置兼容模式。

     

默认情况下,分发机制不向后兼容。此标志将仿真器设置为兼容模式,具有较早的Erlang / OTP版本ReleaseNumber。版本号必须在<current release>-2..<current release>范围内。这限制了模拟器,使其可以与运行早期版本的Erlang节点(以及C节点和Java节点)进行通信。

     

注意
  确保分布式Erlang系统的所有节点(Erlang-,C-和Java节点)具有相同的Erlang / OTP版本,或者来自两个不同的Erlang / OTP版本X和Y,其中所有Y节点都具有兼容模式X.

the erl man page。虽然在实践中你将不使用这个标志,并使用更宽版本的跨度 - 但它不能保证工作。