[英]Is it possible to run different Erlang OTP version at the same time?
I am trying to add Apple's voip push notification into our app. 我正在尝试将Apple的voip推送通知添加到我们的应用程序中。 Our backend provider is written by Erlang's Ejabberd server with apns4erl server 1.0.4. 我们的后端提供程序由Erlang的Ejabberd服务器和apns4erl服务器1.0.4编写。
Currently, the apns4erl 2 has the capability to send voip push notification. 目前,apns4erl 2具有发送voip推送通知的能力。 But it require OTP 19+ to compile and our system is running on OTP 17.3. 但它需要OTP 19+进行编译,我们的系统在OTP 17.3上运行。
So may I know is that possible to run these two OTP at the same time? 所以我可以知道是否可以同时运行这两个OTP? I can't upgrade OTP to 19+. 我无法将OTP升级到19+。 And new library require 19+. 新图书馆需要19岁以上。
Are there good way to make this requirement possible or I need to porting the new library into our old one? 是否有可能使这个要求成为可能,或者我需要将新库移植到旧库中?
Thanks, 谢谢,
Eric 埃里克
Keep in mind while reading this that you should really find a way to update your existing service to keep up to date with newer runtimes. 请注意,在读这是你应该找到一种方法来更新现有服务,以跟上较新的运行时间。 I've dealt with being stuck on a legacy runtime only because someone thought they needed to fork a particular module somewhere in a way that made it impossible to upgrade -- and that was just a nightmare. 我只是因为有人认为他们需要以一种无法升级的方式将某个特定模块分叉 - 而这只是一场噩梦。
Yes, I just confirmed that you can connect an R17 and an R20 node via disterl and send messages: 是的,我刚刚确认您可以通过disterl连接R17和R20节点并发送消息:
R17 node: 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 node: 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
Note that above the R20 node was started first , so that was the version of EPMD that was running. 需要注意的是,R20节点上方开始第一次 ,所以这是所运行的EPMD的版本。 I have no idea whether that would matter, nor do I know if EPMD has changed between R17 and R20. 我不知道这是否重要,我也不知道EP17D是否在R17和R20之间发生了变化。
This is all undocumented functionality . 这是所有未记录的功能 。 Read below for a much more future-proof way to do this. 阅读下面的一个更加面向未来的方式做到这一点。
The documented way to connect two nodes of different versions is with the +R
runtime flag. 记录的连接不同版本的两个节点的方法是使用+R
运行时标志。 I regard this as a wildly unreliable hack (precisely as unreliable as what I demonstrated above) unless you've tested it thoroughly first -- and it may have unintended side effects depending on the versions involved (and no telling what is coming in the future). 我认为这是一个非常不可靠的黑客(正如我上面所说的那样不可靠),除非你先彻底测试过它 - 它可能会产生意想不到的副作用,具体取决于所涉及的版本(并且不知道将来会发生什么) )。 But this is an actual runtime flag and it obviously exists for a reason. 但这是一个实际的运行时标志 ,显然存在是有原因的。 See legoscia's answer for more detail about this. 有关详细信息,请参阅legoscia的答案 。
Whether or not two versions of Erlang's runtime are compatible over disterl, writing network applications in Erlang is really easy . 无论两个版本的Erlang运行时是否与disterl兼容,在Erlang中编写网络应用程序都非常简单 。 You can always connect two of any different things over TCP. 您始终可以通过TCP连接两个不同的东西。
The simple solution to this would be to write a network application in Erlang using the current version of Erlang (R20.1 at the moment) that receives Apple voip pushes, and forwards them to your main application. 对此的简单解决方案是使用当前版本的Erlang(目前为R20.1)在Erlang中编写一个网络应用程序,该应用程序接收Apple voip推送,并将它们转发到您的主应用程序。
Write: 写:
Treat the Apple VOIP service within your system as if it exists as a native part of your application . 将系统中的Apple VOIP服务视为应用程序的本机部分 。 The socket handler in the R17 node is the VOIP service. R17节点中的套接字处理程序是 VOIP服务。 Make sure you write its interface functions with that in mind -- later if you can migrate your code to R20 then you won't have to worry with this detail because it will be already abstracted by the internal protocol in Erlang. 确保编写其接口函数时考虑到这一点 - 以后如果您可以将代码迁移到R20,那么您不必担心这个细节,因为它已经被Erlang中的内部协议抽象化了。
As for the push updates themselves, you can create whatever sort of protocol you want. 至于推送更新本身,您可以创建任何类型的协议。
Erlang's external term format has not changed between R17 and R20, so you will be able to send native messages between the two nodes by having the Apple VOIP side socket handler (on the R20 node) do something like: Erlang的外部术语格式在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").
And on the receiving node (the R17 node): 在接收节点(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.
You could write the R17 side as a gen_server also, listening for: 您也可以将R17侧写为gen_server,并监听:
handle_info({tcp, Socket, Bin}, State = #s{socket = Socket}) ->
%% whatever
I just happen to most often see socket handling processes as proc_lib
processes instead of gen_servers most of the time. 我碰巧经常看到套接字处理过程作为proc_lib
进程而不是gen_servers大多数时间。 But it doesn't matter in most cases. 但在大多数情况下并不重要。
Another approach is to use binaries: 另一种方法是使用二进制文件:
notify_node(Socket, VOIP_Data) ->
Message = <<"PUSH ", VOIP_Data>>,
ok = gen_tcp:send(Socket, Message),
log(info, "Message sent").
And on the receiving node (the R17 node): 在接收节点(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.
It really depends on the nature of VOIP_Data
. 这实际上取决于VOIP_Data
的性质。 If it is a binary itself and the R20 Apple push service should just pass it along without inspecting it, then the raw binary method is easy. 如果它本身就是二进制文件并且R20 Apple推送服务应该只是传递它而不检查它,那么原始二进制方法很容易。 If the R20 side is going to be interpreting the message and converting it to an Erlang message of its own then you'll do much better with the binary_to_term/1
/ term_to_binary/2
form. 如果R20侧将要解释的消息,并将其转化为自身的二郎山消息,那么你会做的更好 binary_to_term/1
/ term_to_binary/2
形式。
zxq9's answer covers everything you need to know for this particular situation. zxq9的答案涵盖了您在这种特殊情况下需要了解的所有内容。 I just want to mention the +R
flag: 我只想提一下+R
标志:
+R ReleaseNumber
Sets the compatibility mode. 设置兼容模式。The distribution mechanism is not backward compatible by default. 默认情况下,分发机制不向后兼容。 This flag sets the emulator in compatibility mode with an earlier Erlang/OTP release
ReleaseNumber
. 此标志将仿真器设置为兼容模式,使用较早的Erlang / OTP版本ReleaseNumber
。 The release number must be in the range<current release>-2..<current release>
. 版本号必须在<current release>-2..<current release>
。 This limits the emulator, making it possible for it to communicate with Erlang nodes (as well as C- and Java nodes) running that earlier release. 这限制了模拟器,使其可以与运行早期版本的Erlang节点(以及C节点和Java节点)进行通信。Note 注意
Ensure that all nodes (Erlang-, C-, and Java nodes) of a distributed Erlang system is of the same Erlang/OTP release, or from two different Erlang/OTP releases X and Y, where all Y nodes have compatibility mode X. 确保分布式Erlang系统的所有节点(Erlang-,C-和Java节点)具有相同的Erlang / OTP版本,或者来自两个不同的Erlang / OTP版本X和Y,其中所有Y节点都具有兼容模式X.
See the erl
man page . 请参见erl
手册页 。 Though in practice you will get away with not using this flag, and using wider version spans - it's just not guaranteed to work. 虽然在实践中你会逃避不使用这个标志,并使用更宽版本的跨度 - 它不能保证工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.