Elixir Ranch:Embeddedモード

4455 ワード

埋め込みモードでは、Ranchリスナーをモニタツリーに直接挿入できます.アプリケーション全体の他の部分が削除する場合、リスナーを閉じる方法により、より良いフォールトトレランス制御を提供することができる.
埋め込み(Embedding)
Ranchを自分のアプリケーションに埋め込むには、サブプロセス仕様をモニタツリーに簡単に追加するだけです.このプロセスは、アプリケーションの1つ(一般的には最上位レベルのSupervisorで、アプリケーションが複雑であれば、他のレイヤである可能性もある)Supervisorinit/1関数で完了する.
埋め込みについては、Ranchは少なくとも2種類のサブプロセス仕様を要求する.まず、ranch_supをモニタツリーに追加する必要があり、1回だけ、複数のリスナーを使用するもよい.その後、各リスナーにサブプロセス仕様を追加する必要がある.
80ポートのHTTPリスナーや443ポートのHTTPSリスナーなど、複数のリスナーを追加することができる.
Ranchは簡単な補助関数ranch:child_spec/6を提供し、リスナーのサブプロセス仕様を取得する.その動作はranch:start_listener/6と類似しているが、プロセスを起動せず、サブプロセス仕様を返すだけである.ranch_supに対して、サブプロセス規範は十分に簡単で、補助関数を必要としない.
次の例では、ranch_supと別のアプリケーションのモニタツリーに1つのリスナーを追加する.
直接Ranchをモニタツリーに埋め込む
init([]) ->
    RanchSupSpec = {
        ranch_sup, 
        {ranch_sup, start_link, []}, 
        permanent, 
        5000, 
        supervisor, 
        [ranch_sup]
    },
    ListenerSpec = ranch:child_spec(
        echo, 
        100, 
        ranch_tcp, 
        [{port, 5555}], 
        echo_protocol, 
        []
    ),
    {ok, {{one_for_one, 10, 10}, [RanchSupSpec, ListenerSpec]}}.

必要に応じて複数のリスナーを追加できますが、ranch_supサブプロセス仕様は1つしかありません.
ElixirのSupervisor実現
埋め込み前のSupervisor
require Logger
defmodule RanchEmbededMode.Supervisor do
  use Supervisor

  def start_link do
    Logger.debug "Start supervisor."
    Supervisor.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init([]) do
    children = [
      worker(RanchEmbededMode.TcpAcceptor, []),
    ]
    Logger.debug "supervisor child spec #{inspect children}"
    opts = [strategy: :one_for_one, max_restarts: 3]
    Logger.debug "strategy #{inspect opts}"
    supervise(children, opts)
  end
end

埋め込み前のモニタツリー構造
埋め込み前Ranchは独立したApplicationである
埋め込み前のRanchEmbededModeアプリケーションモニタツリー構造
埋め込みSupervisorEmbed
require Logger
defmodule RanchEmbededMode.SupervisorEmbed do
  use Supervisor

  def start_link do
    Logger.debug "Start supervisor."
    Supervisor.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init([]) do
    children = [
      ranch_sup(),
      ranch_embeded_mode_listener()
    ]
    Logger.debug "supervisor child spec #{inspect children}"
    opts = [strategy: :one_for_one, name: __MODULE__]
    Logger.debug "strategy #{inspect opts}"
    supervise(children, opts)
  end

  def ranch_sup do
    supervisor(:ranch_sup, [], [shutdown: 5000])
  end

  @doc """
  Ranch                       Child Spec
  """
  def ranch_embeded_mode_listener do
    :ranch.child_spec(
      :ranch_embeded_mode_listener,
      10,
      :ranch_tcp,
      [port: 5555],
      RanchEmbededMode.TcpProtocolHandler, []
    )
  end
end

埋め込み後のモニタツリー構造は、独立したRanch Applicationが存在しなくなった.
特に注意すべき点
Ranchが独立したアプリケーションとして機能する場合は、Ranchが現在のアプリケーションよりも前に起動することを確認してください.Ranchが埋め込みモードとして動作する場合は、 mix.exsまたは他の場所でRanchを起動することを確認してください.現在のアプリケーションのSupervisorがRanchを起動し、現在のアプリケーションモニタツリーのサブツリーとして動作することを担当します.
独立モードでmix.exsはranchを早期に起動し、次のエラーを報告します.
埋め込みモードでmix.exsでranchを事前に起動し、次のエラーを報告しました.
提案:モニタツリーの設計の面では、ranch_supが切られたときに、すべてのリスナーを再起動することを確保する.詳細はRanch公式サイトGuideのInternal章を参照してください.
サンプルプログラム
本明細書のコード例はhttps://github.com/developerworks/ranch_embeded_modeにある
また、プロジェクトに好きな名前を付けたい場合は、次の手順に従います.
git clone https://github.com/developerworks/ex_ranch_server_tasks.git
cd ex_ranch_server_tasks
mix archive.build
mix archive.install                #   Y  
mix ranch.new  --sup #            

独立モードRanchEmbededMode.Supervisor.start_linkを使用して埋め込みモードを開始RanchEmbededMode.SupervisorEmbed.start_linkを使用して起動
参考資料
https://github.com/ninenines/ranch/blob/master/doc/src/guide/embedded.asciidoc