1

Erlang VM のホット コード リロード機能をテストするために、非常に基本的な Elixir スーパーバイザーとワーカーを作成しました。これがスーパーバイザーです:

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を読みましたが、著者は、実行中のコードは実行し続ける必要があり、アップグレード後に行われた外部呼び出しのみが新しいバージョンで提供されると述べています。

では、なぜ労働者を殺すのですか?

4

0 に答える 0