我创建了一个非常基本的 Elixir 主管和工作人员,以测试 Erlang VM 的热代码重载功能。这是主管:
defmodule RelTest do
use Application
# See http://elixir-lang.org/docs/stable/elixir/Application.html
# for more information on OTP Applications
def start(_type, _args) do
import Supervisor.Spec, warn: false
port = Application.get_env(:APP_NAME, :listen_port, 9000)
{:ok, socket} = :gen_tcp.listen(port, [:binary, active: false, reuseaddr: true])
# Define workers and child supervisors to be supervised
children = [
# Starts a worker by calling: RelTest.Worker.start_link(arg1, arg2, arg3)
# worker(RelTest.Worker, [arg1, arg2, arg3]),
worker(Task, [fn -> TestListener.start(socket) end])
]
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: RelTest.Supervisor]
Supervisor.start_link(children, opts)
end
end
基本上,我正在启动一个任务工作者,即:
defmodule TestListener do
require Logger
def start(socket) do
{:ok, client} = :gen_tcp.accept(socket)
Logger.info "A client connected"
Task.async(fn -> loop(client) end)
start(socket)
end
def loop(socket) do
case :gen_tcp.recv(socket, 0) do
{:ok, _} ->
say_hello(socket)
Logger.info "Said hello to client ;)"
loop(socket)
{:error, _} ->
Logger.info "Oops, client had error :("
:gen_tcp.close(socket)
end
end
def say_hello(socket) do
:ok = :gen_tcp.send(socket, <<"Hey there!\n">>)
end
end
这是版本0.1.0
。所以我运行这些:
MIX_ENV=prod mix compile
Mix_ENV=prod mix release
我得到了一个很好的释放。我运行它,./rel/rel_test/bin/rel_test console
一切正常。现在我要修改代码和版本,所以这里是0.1.1
监听器的版本:
defmodule TestListener do
require Logger
def start(socket) do
{:ok, client} = :gen_tcp.accept(socket)
Logger.info "A client connected"
Task.async(fn -> loop(client) end)
start(socket)
end
def loop(socket) do
case :gen_tcp.recv(socket, 0) do
{:ok, _} ->
say_hello(socket)
Logger.info "Said hello to client ;)"
loop(socket)
{:error, _} ->
Logger.info "Oops, client had error :("
:gen_tcp.close(socket)
end
end
def say_hello(socket) do
:ok = :gen_tcp.send(socket, <<"Hey there, next version!\n">>)
end
end
现在我跑
MIX_ENV=prod mix compile
Mix_ENV=prod mix release
并appup
创建成功,然后进行热升级
./rel/rel_test/bin/rel_test upgrade "0.1.1"
并且升级有效,但升级后它会杀死我的听众。
我用一个nc localhost 9000
(9000 是监听器的端口)进行了测试,保持连接并运行升级命令。连接被终止,我在控制台中收到一条消息:
=SUPERVISOR REPORT==== 31-Aug-2016::23:40:09 ===
Supervisor: {local,'Elixir.RelTest.Supervisor'}
Context: child_terminated
Reason: killed
Offender: [{pid,<0.601.0>},
{id,'Elixir.Task'},
{mfargs,
{'Elixir.Task',start_link,
[#Fun<Elixir.RelTest.0.117418367>]}},
{restart_type,permanent},
{shutdown,5000},
{child_type,worker}]
那么为什么会发生这种情况呢?是我缺少的东西,还是预期的行为?不就是热代码重载的用例吗?
我读过LYSE,但作者说运行代码应该继续运行,只有升级后进行的外部调用才能使用新版本。
那为什么要杀工人?