ちょっとしたHTTPの処理を受けるサーバを Plug を使って実装してようとしたら、 Plug.Adapters.Cowboy.child_spec() をすることになりました。また、trotも少し処理を追ってみると同様なところに行き着く。
ふと作業している途中で、Phoenixだと、1 request – 1 processとなるendpointの処理は結局はどこが処理してそうなっているのだろう、という疑問がわいたので、 すべきことを横に置いて さかのぼってみました。
過去、似たようなところとして以下のようなものを追っていました。
開始地点
ひとまず、雑に Plug.Adapters.Cowboy で検索してみました。これは、Elixirの機構を使っているなら、最終的に同様にPlugにいくだろう、とのことから。
すると、Plug.Adapters.Cowboy.Handler なんかが検索に引っかかります。
この中から、 Phoenix.Endpoint.CowboyHandler の child_spec の中で使われているのを見つけました。この child_spec は、Subversion Treeの中で呼ばれます。
同様に、このHandlerをみてみると、この行にて、
Plug.Adapters.Cowboy.child_spec(scheme, endpoint, [], config)
が呼ばれていることがわかります。つまり、Phoenixのendpointの処理は、最終的にはPlugを使い、Cowboyへと向かっているのですね。
なるほど。
Subversion Treeを遡る
もう少し、今度はSubversionがどのように流れているのかを追ってみました。つまり、 Phoenix.Endpoint.CowboyHandler がSubversion Treeの中で呼ばれるところを探す、です。
検索してみると、Phoenix.Endpoint.Serverで、
@handler Phoenix.Endpoint.CowboyHandler
として定義され、この@handler が同じファイル内の initの箇所で呼ばれています。
じゃあ、このPhoenix.Endpoint.ServerをどのSubervionが呼んでいるのか?というと、Phoenix.Endpoint.Adapterで呼ばれていました。
もう少しさかのぼると、 Phoenix.Endpoint.Adapter は Phoenix.Endpoint の def server()内で stat_linkされるようです。この server() は、同じファイルの __using__ で呼ばれているので、Phoenix.Endpoint をuseするところがスタート地点ぽい。
ここまでくるともう大体分かって、最終的には phoenix new のときに生成されるテンプレートの defmodule <%= application_module %>.Endpoint do が定義されるここ が出発点になります。確かに、 Phoenix.Endpoint を use していることがわかり、なるほど、という感じ。
締め
Phoenixの 1 request 1 processは、すべてを網羅しているわけではないのですが、おそらくendpointを処理するPlug経由のCowboyの恩恵に寄るものぽいです。
Cowboyへの理解を深めると良いのか。Welcome to Erlang 🙂