2

サード パーティの Web サービスと対話する Rebus メッセージ ハンドラーがあります。すぐには制御できない理由により、この WCF サービスは、独自のデータベースでデータベース デッドロックが発生したため、頻繁に例外をスローします。その後、Rebus はこのメッセージを 5 回処理しようとします。これは、ほとんどの場合、5 回のうちの 1 回が幸運であり、デッドロックに陥らないことを意味します。しかし、メッセージがデッドロックに続いてデッドロックになり、エラー キューに入ることがよくあります。

長期的な目標となるデッドロックの原因を修正する以外に、次の 2 つのオプションが考えられます。

  1. 成功するまで、この特定のメッセージ タイプのみを試してください。できればタイムアウトを設定できるので、継続的に試行してプロセスをさらに詰まらせるのではなく、「デッドロックが 5 回発生した場合は 5 分後に再試行してください」とします。私はすでに Thread.Sleep(random) を実行してメッセージをいくらか広めていますが、5回試行してもあきらめます。

  2. この特定のメッセージ タイプを、メッセージを処理するワーカーが 1 つしかない別のキューに送信して、これが並列ではなく逐次的に行われるようにします。現在の構成では 8 つのワーカー スレッドを使用していますが、Web サービスが同時に呼び出され、メッセージが相互に干渉するため、デッドロックの状況が悪化するだけです。

オプション#2が私の好みですが、これが可能かどうかはわかりません。現在、受信側の構成は次のようになっています。

var adapter = new Rebus.Ninject.NinjectContainerAdapter(this.Kernel);

var bus = Rebus.Configuration.Configure.With(adapter)
    .Logging(x => x.Log4Net())
   .Transport(t => t.UseMsmqAndGetInputQueueNameFromAppConfig())
   .MessageOwnership(d => d.FromRebusConfigurationSection())
   .CreateBus().Start();

そして、受信側の .config :

<rebus inputQueue="app.msg.input" errorQueue="app.msg.error" workers="8">
  <endpoints>
  </endpoints>
</rebus>

構成からわかることから、「リッスン」する入力キューを 1 つしか設定できません。流暢なマッピング API を介してこれを行う方法を実際に見つけることもできません。それも入力キューとエラーキューを1つだけ取るようです:

.Transport(t =>t.UseMsmq("input", "error"))

基本的に、私が探しているのは、次のようなものです。

<rebus workers="8">
  <input name="app.msg.input" error="app.msg.error" />
  <input name="another.input.queue" error="app.msg.error" />
</rebus>

私の要件を処理する方法に関するヒントはありますか?

4

1 に答える 1

2

saga と Rebus のタイムアウト サービスを利用して、ニーズに合った再試行戦略を実装することをお勧めします。このようにして、Rebus 対応の Web サービス ファサードで、次のようなことができます。

public void Handle(TryMakeWebServiceCall message)
{
    try
    {
        var result = client.MakeWebServiceCall(whatever);

        bus.Reply(new ResponseWithTheResult{ ... });
    }
    catch(Exception e)
    {
        Data.FailedAttempts++;

        if (Data.FailedAttempts < 10)
        {
            bus.Defer(TimeSpan.FromSeconds(1), message);
            return;
        }

        // oh no! we failed 10 times... this is probably where we'd
        // go and do something like this:
        emailService.NotifyAdministrator("Something went wrong!");
    }
}

Data魔法のように利用可能になり、呼び出し間で永続化される saga データはどこにありますか。

サガを作成する方法のインスピレーションについては、時間の経過とともに発生する調整に関する wiki ページをチェックしてください。ここでは、サービスがローカルに保存された状態 (つまり、あなたのケースでは失敗した試行の数) を持つ方法の例を見ることができます。処理メッセージ間で使用できます。

作業を行うときはbus.Defer、次の 2 つのオプションがあります。1) 外部のタイムアウト サービス (私は通常、各サーバーに 1 つインストールしています) を使用するか、2) タイムアウト サービスとして「自分自身」を使用するだけです。

設定時に、

Configure.With(...)
    .(...)
    .Timeouts(t => // configure it here)

StoreInMemoryStoreInSqlServerStoreInMongoDbStoreInRavenDb、またはのいずれかを指定できますUseExternalTimeoutManager

(1) を選択した場合は、Rebus コードをチェックアウトし、自分でRebus.Timeoutをビルドする必要があります。これは基本的に、内部に Rebus エンドポイントを持つ構成可能な Topshelf 対応のコンソール アプリケーションです。

この作業を行うためにさらにサポートが必要な場合はお知らせください -bus.Deferあなたのシステムが素晴らしいものになり、他のすべてのシステムをダウンさせる小さな不具合をすべて克服できるようになります:)

于 2013-05-30T19:03:44.070 に答える