Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Phoenix.PubSubの紹介と活用を考える

 Phoenix.PubSubの紹介と活用を考える

2021/10/26 fukuoka.ex#47:Elixirお茶会 での登壇資料です

https://fukuokaex.connpass.com/event/227466/

302e60b4d42787b4a39de4a3a80cfc9d?s=128

shozo koga

October 26, 2021
Tweet

More Decks by shozo koga

Other Decks in Programming

Transcript

  1. Phoenix.PubSub の紹介と活用を 考える 2021.10.26 fukuoka.ex#47 :Elixir お茶会〜Phoenix を学ぼう編

  2. About Me @koga1020_ @koga1020 koga1020.com 👨‍💻 自己紹介 古賀 祥造(koga1020 )

    福岡在住のバックエンドエンジニア(最近はマネジメント寄り) fukuoka.ex 管理人 💡 最近の興味関心 Elixir ・Phoenix を使ったWeb アプリケーション開発 マイクロサービスの実現。実装パターンの学習 ユーザーも開発者もハッピーなプロジェクト・プロダクトマネジメント 美味しいご飯・美味しいお酒 🍶 マイホームで快適に過ごすこと 🏠 キャンプ・アウトドア用品 ⛺
  3. アジェンダ PubSub パターンについて Phoenix.PubSub の導入 PubSub を動かしてみる ユースケースを考える

  4. PubSub パターンについて

  5. PubSub パターン 出版(Publish)- 購読(Subscribe) パターン Publisher は入力チャネルを介してメッセージを送信 Subscriber のためにメッセージを入力チャネルから出力チャネルにメッセージをコピー Subscriber

    は関心のあるメッセージを受け取る [1] 1. https://docs.microsoft.com/ja-jp/azure/architecture/patterns/publisher-subscriber
  6. PubSub パターンの利点 Publisher とSubscriber を切り離して管理、疎結合にできる Publisher は、メッセージを送信するのみ それをどこの誰がSubscribe しているかは関心がない Publisher

    の処理を小さくできる(応答性の向上) 遅延処理やスケジュールされた処理も可能 詳しくは クラウド設計パターン - パブリッシャーとサブスクライバーのパターン 参照
  7. Phoenix.PubSub を使ってPubSub を実装してみる

  8. 実装イメージ(再掲) 真ん中のブローカーがPhoenix.PubSub が担うイメージ 1. https://docs.microsoft.com/ja-jp/azure/architecture/patterns/publisher-subscriber ↩︎ [1]

  9. Phoenix.PubSub の導入 project を作成した段階でsupervision tree に追加されている # Start the PubSub

    system {Phoenix.PubSub, name: Sample.PubSub}, # lib/sample/application.ex @impl true def start(_type, _args) do children = [ # Start the Ecto repository Sample.Repo, # Start the Telemetry supervisor SampleWeb.Telemetry, # Start the Endpoint (http/https) SampleWeb.Endpoint # Start a worker by calling: Sample.Worker.start_link(arg) # {Sample.Worker, arg} ] # See https://hexdocs.pm/elixir/Supervisor.html # for other strategies and supported options opts = [strategy: :one_for_one, name: Sample.Supervisor] Supervisor.start_link(children, opts) end
  10. Subscriber を追加する "user_event" をsubsribe するSubsriber1 を作成 IO.puts "get message: #{inspect(message)}

    at #{__MODULE__}" # lib/sample/subscriber1.ex defmodule Sample.Subscriber1 do use GenServer def init(_) do Phoenix.PubSub.subscribe(Sample.PubSub, "user_event") {:ok, nil} end def start_link(opts) do GenServer.start_link(__MODULE__, opts) end def handle_info(message, state) do {:noreply, state} end end
  11. Subscriber を追加する product_event をsubsribe するSubscriber2 を作成 Phoenix.PubSub.subscribe(Sample.PubSub, "product_event") # lib/sample/subscriber2.ex

    defmodule Sample.Subscriber2 do use GenServer def init(_) do {:ok, nil} end def start_link(opts) do GenServer.start_link(__MODULE__, opts) end def handle_info(message, state) do IO.puts "get message: #{inspect(message)} at #{__MODULE__}" {:noreply, state} end end
  12. application tree に追加する def start(_type, _args) do children = [

    # Start the Ecto repository Sample.Repo, # Start the Telemetry supervisor SampleWeb.Telemetry, # Start the PubSub system {Phoenix.PubSub, name: Sample.PubSub}, # Start the Endpoint (http/https) - SampleWeb.Endpoint + SampleWeb.Endpoint, # Start a worker by calling: Sample.Worker.start_link(arg) # {Sample.Worker, arg} + Sample.Subscriber1, + Sample.Subscriber2 ]
  13. 実行してみる user_event にはSubscriber1 が、product_event にはSubscriber2 がそれぞれ応答していることがわかる $ iex -S mix

    iex(2)> Phoenix.PubSub.broadcast(Sample.PubSub, "product_event", %{id: 456}) :ok get message: %{id: 456} at Elixir.Sample.Subscriber2 iex(1)> Phoenix.PubSub.broadcast(Sample.PubSub, "user_event", %{id: 123}) :ok get message: %{id: 123} at Elixir.Sample.Subscriber1
  14. どんな使い方が考えられる?

  15. Webhook e.g. GitHub をイメージしてみる branch が削除されたら、X に通知 issue にコメントがついたら、X とY

    に通知 …etc こんな感じで実装できそう? # Subsriber iex> PubSub.subscribe(Sample.PubSub, "repo_event:koga1020") # Publisher iex> PubSub.broadcast( ...> Sample.PubSub, ...> "repo_event:koga1020", ...> {:branch, :deleted, %{repo: "koga1020/sample", branch: "feature1", deleted_at: ~U[2021-10-24 14:06:23.666118Z]}} ...> )
  16. CallBack のように使う ActiveRecord でいう after_update っぽく使う 「ユーザーデータが更新された」というイベントを配信する 保存後に追加で何を行うかはPublisher は関与しない def

    update_user(%User{} = user, attrs) do user |> User.changeset(attrs) |> Repo.update() |> tap( {:ok, user} -> Phoenix.PubSub.broadcast(Sample.PubSub, "user:#{user.id}", {:user_update}, user) error -> error end) end ` `
  17. パターンの勘所 あるドメインイベントが発生したときに、そのイベントのデータを利用する コンシューマー(=Subscriber) が多い場合に有用 Channels のユースケース=PubSub のユースケースと解釈しても良さげ hexdocs の例: Chat

    rooms and APIs for messaging apps Breaking news, like "a goal was scored" or "an earthquake is coming" Tracking trains, trucks, or race participants on a map Events in multiplayer games Monitoring sensors and controlling lights Notifying a browser that a page’s CSS or JavaScript has changed (this is handy in development) [1] 1. https://hexdocs.pm/phoenix/channels.html
  18. PubSub パターンが不適切な場合 https://docs.microsoft.com/ja-jp/azure/architecture/patterns/publisher-subscriber より 作成側アプリケーションの大きく異なる情報を必要とするコンシューマーが、数人だけしかいない場合。 アプリケーションが、ほぼリアルタイムの、コンシューマーとの対話を必要とする場合。

  19. まとめ Phoenix.PubSub を使ったPubSub パターンの実装について紹介 プロジェクトを作成しただけでこの環境が整っているのは非常に便利 設計の勘所は必要そうだが、うまく使えると大きな武器になるかも?