2つのGenServerモジュール - AとBがあります。BはAを監視して、Aがクラッシュしたときに:DOWN
メッセージを受信するようにhandle_info
を実装しています。handle_callで発生するトラッププロセスクラッシュ
私のコード例では、BはAに同期要求(handle_call
)を行います。要求の処理中にAがクラッシュします。 Bは:DOWN
メッセージを受信するはずですが、そうではありません。どうして?
handle_call
をhandle_cast
に置き換えたとき、Bは:DOWN
というメッセージを受信しました。 handle_call
が動作しないのに対し、handle_cast
はなぜですか?
これは単純な例のコードである:私のコード例で
defmodule A do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, :ok, name: :A)
end
def fun(fun_loving_person) do
GenServer.call(fun_loving_person, :have_fun)
end
def init(:ok) do
{:ok, %{}}
end
def handle_call(:have_fun, _from, state) do
######################### Raise an error to kill process :A
raise "TooMuchFun"
{:reply, :ok, state}
end
end
defmodule B do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, :ok, name: :B)
end
def spread_fun(fun_seeker) do
GenServer.call(:B, {:spread_fun, fun_seeker})
end
def init(:ok) do
{:ok, %{}}
end
def handle_call({:spread_fun, fun_seeker}, _from, state) do
######################### Monitor :A
Process.monitor(Process.whereis(:A))
result = A.fun(fun_seeker)
{:reply, result, state}
rescue
_ -> IO.puts "Too much fun rescued"
{:reply, :error, state}
end
######################### Receive :DOWN message because I monitor :A
def handle_info({:DOWN, _ref, :process, _pid, _reason}, state) do
IO.puts "============== DOWN DOWN DOWN =============="
{:noreply, state}
end
end
try do
{:ok, a} = A.start_link
{:ok, _b} = B.start_link
:ok = B.spread_fun(a)
rescue
exception -> IO.puts "============= #{inspect exception, pretty: true}"
end
ありがとうございました!素晴らしい説明。 別のモジュール(A)に依存するRabbitMQメッセージコンシューマ(モジュールB)があります。 Aがクラッシュし、Bがメッセージを拒否して再キューできないときに、メッセージがリムボウになることは望ましくありません。あなたはもっと良いアプローチを知っていますか? –
1つの方法は、Aが失敗した場合にBにメッセージをドロップさせ、メッセージが期限切れになり、RabbitMQによって自動的に再キューされるようにすることです(キューが適切に構成されていると仮定します)。もう1つは、上記の「キャッチ」戦術を使用して、メッセージを数回再試行してからやめてください。さらに別の方法は、Bがそのメッセージの処理を担当するプロセスにメッセージを渡し、Bを解放して他のメッセージを消費し続け、成功するまでそのプロセスを再試行させることです。しかし、メッセージの順序が重要でない場合にのみ動作し、次にフロー制御の問題があります。 – bitwalker
私の意見では、Bを拒否/再キューする方法を見つけ出す方が良いでしょう。あなたは出口を捕まえています)、または失敗したメッセージをドロップして、自動的にメッセージを期限切れにして再キューに入れることができます。メッセージの順序が重要な場合は、再試行がより良い選択となる可能性があります。 – bitwalker