[Elixir] GenServerのCallとCast


この記事は Elixir その2 Advent Calendar 2020 15日目です。

前日は、「[Elixir] "Hello"と'Hello'」でした。

本日もGenServer関連の話題です。castcallについてのベストプラクティスについて考えたかったので、これをテーマにメモにまとめまることにしました。

はじめに

GenServerのcastcallの使い分けは、Elixirを覚えたての頃は単純に思えました。結果を気にしないのであれば、castって感じで。
しかしながら、実際はそんな単純な話ではありません。castには投げた処理が成功したのかどうかがわからないという不安な要素があり、それで本当に良いのかきっちり考慮したいです。

結果がわからない |> 整合性に問題がでてくるかも |> ???

この件について、個人的にElixir in Actionの著者Saša Jurićさんのアドバイスがわかりやすく気に入ってます。

Saša Jurićさんのアドバイス

第7章や11章でガイドラインを提示されてます。

  • 迷ったらcallを使用する。そうすることによりシステム整合性が促進される。(簡単に整合性促進)
  • パフォーマンスに問題が出てきたときに必要であれば、後日簡単にcastに変更できる。(整合性を犠牲にパフォーマンス促進)
  • 処理の負荷が大きい場合、キュープロセス(中間プロセス)を用意し、そこから結果についての通知を2回(受付、完了)受けるようにすることもできる。(整合性とパフォーマンスの両立)
  • 自前で中間プロセスを立ててもよいが、複雑なシステムの場合GenStageが便利。

詳しくはElixir in Actionを御覧ください。

call - 「ブロックする」リクエスト

長所

  • 整合性を促進
  • 発信者プロセスは結果を受信できる。

短所

  • 即応性の低下。
  • 発信者プロセスはワーカープロセスのスループットに依存。

cast - 「投げて忘れる」リクエスト

長所

  • 即応性を促進。
  • 発信者プロセスをブロックしない。

短所

  • 整合性の低下
  • 発信者プロセスは投げたリクエストの結果がどうなったのかわからない。

そのプロセス必要がないかも?

... In any case, for something as trivial as sending an email in Elixir, I would send the e-mail within the request, especially if the user needs to open up the e-mail before proceeding. - José Valim

José Valimさんは、ちょっとしたメール送信するくないなら、リクエストのプロセス内処理するでと言ってます。

さいごに

今後更に新しいことを学んだら、どんどん更新していこうと思います。Elixir楽しい。


明日は「[Elixir] GenServerのアイドルタイムアウト」です。引き続き、Elixirを楽しみましょう。

Happy coding!