Elixir
https://gyazo.com/3e628cf5621b1d0994a567f306f60cff
HTTPサーバライブラリを探す
条件
簡単、メンテされている、Elixir製
候補
Ace/raxx
ElixirではGenServer側にchild_specを設定する
Applicationのトップレベルだと、そのままsupervisor:start_link/2するのを推奨
それ以外はコールバックモジュールを定義するのが推奨
simple_one_for_oneは非推奨でDynamicSuperviosrを使うらしい
テスト時には基本的にアプリケーションが起動している
mix test --no-startで回避できる
テストモジュール毎に設定したいが見当たらない
ここではコールバックでの使用ではなく、直接supervision treeに加えている
simple_one_for_oneがややこしいので消すために導入されたらしい
Erlangと違い、子のモジュールは複数個使える
デバッグ用にとりあえず使う
プロダクション向けのパッケージを使うんだとerlの-configオプションに渡さないといけなさそう?
Erlangに比べて関数でのパターンマッチが冗長に感じる
typespecはそれぞれ書いていいようだった
ここはErlangよりもわかりやすい
Mockテスト
Erlangのmeckみたいなやつ
Elixir でのモックに対する単純な解答は、使うな、です。本能のままにモックへと手を伸ばしているかもしれませんが、 Elixir のコミュニティや正当な理由からはとても推奨されていないものです。
ビヘイビアとコールバックを使うべき、とのこと
モックのライブラリはいくつかあるぽかった
クラスタを手軽に組みたい
Applicationモジュールに追記する自動クラスタ構築ライブラリ
ノードのjoin/leaveもイベントとして扱えるようなことが書いてあるが自動でクラスタを組んでくれるのみ
libclusterは元はこのライブラリの一部だったぽい
docker-compose.ymlの書き方を参考にする
Elixirのパイプラインはマクロで実現されている
また、カリー化や中置演算子のユーザ定義ができないので演算子というよりは構文らしい
演算子と構文の違いがよくわかっていない
do end はキーワードリストのシンタックスシュガー
関数呼び出し前に評価されるので、関数にブロックを渡すことはできない
ブロックを渡したいときにはマクロを使う
Elixir で Erlang のログを出す
code:elixir
config :logger,
handle_otp_reports: true,
handle_sasl_reports: true
application で :sasl を先に起動するようにしておくこと
Dialxir で警告が出る
code:elixir
@spec run_test!(any()) :: any()
def run_test!(x) do
if 0 < length(x) do
raise "error"
else
x
end
end
lengthを使うと警告がでる
それ以外だと出ない
Discord での Elixir 使用例
20以上の Elixir サービスがある
同時接続120万ユーザ
秒間260万イベントが WebSocket でやり取りされている
400 から 500 ノードでクラスタを組んでいる
chat infrastructure チーム
-connect_all false オプションを ErlangVM に設定して partially meshed network を etcd を使って構築している
エンジニアは5人で全員入社してから Elixir を始めた
cowboy で WebSocket/TCP を使っている
GenStage も使ってる
Manifold
GenServer から 30,000 PIDs に cast するのが遅すぎたので作ったらしい
ZenMonitor
組み込み monitor の代替
Mnesia をインメモリでpersistent モードで使おうとしたが復旧が遅くて諦めた
Note that the syntactic representation of map() is %{optional(any) => any}, not %{}. The notation %{} specifies the singleton type for the empty map.
map() と %{} は違うもの
code:map.ex
%{a: 2, b: 1}
Enum.map/2 だと tuple list が返るので Map にやりたいときは Map.new/1を使う