[Elixir]1worker、1portでリクエストを待ってHTTPのリクエストをProxyする

HerokuがErlang製のHTTP Proxyを公開しましたね。少し中身見てみたのですが、彼らもForkしたCowboyを使ってProxyを構築しているっぽい。他にも軽く読んでは見たのですが、Erlangも多少読めるようになっててびっくり。

https://github.com/heroku/vegur

話は少し変わって、[Elixir]Elixirで簡単なHTTP Proxyを書いているときに出会ったエラーのメモで、Supervisorのworkerごとに異なるportを待ち受けてそれぞれが独立したproxyとして動作する機構を書いてたのですが、PIDの衝突の発生で思った感じでできてませんでした。

でも、考えるほどにやっぱりできるはずだよなーと思いもう少しやってみました。それと、先ほどのVegurでもやっぱり異なるPortで待ち受ける処理が書いてあって、やっぱり実装間違ってるなと確信。

もう一度考え直してみると、今回は考えた通りに書いていったら期待通り動作することができました。
結局は、 Plug.Adapters.Cowboy.http に対して与えている ref の与え方が間違っていた、という情けないミスでした…

リポジトリ: https://github.com/KazuCocoa/http_proxy

前回の誤り

def start_link(proxy) do
  Plug.Adapters.Cowboy.http __MODULE__, [ref: proxy[:name]], port: proxy[:port].port
end

今回

def start_link(proxy) do
  Plug.Adapters.Cowboy.http(__MODULE__, [], [port: proxy.port, ref: String.to_atom(module_name)])
end

これで、例えば以下のような実装を書いたときに、Supervisorで監視される各々のWorkerが異なるProcessとPortでリクエストを待つことができるようになります。 HttpProxy.Handle のモジュールに、先ほどのCowboyの起動が実装されていることを想定しています。

  def init(:ok) do
    import Supervisor.Spec

    [%{port: 4000, ...}, %{port: 4001, ...}]
    |> Enum.reduce([], fn proxy, acc ->
      module_name = "HttpProxy.Handle#{proxy.port}"
      [worker(HttpProxy.Handle, [[proxy, module_name]], [id: String.to_atom(module_name)]) | acc]
    end)
    |> supervise(strategy: :one_for_one)

  end

修正時のコミット(ファイルの置き換えあり): https://github.com/KazuCocoa/http_proxy/commit/8b5368f15a2e149ac7069a33379e4c190cf93374


Elixir/Erlangさわりはじめて、大学の頃もでしたが、やっぱり私は分散系に対して技術的な興味を持っているのだなーと感じました。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中