1

使用した NServiceBus のバージョン: 2.0.0.1145

質問:

NServiceBus ホストを構成して、自身の公開メッセージを消費 (サブスクライブ) することはできますか?

答え:

可能だと思われますが、次の構成では、サブスクリプションを SubscriptionStorage に挿入しようとしているときに、トランザクションのデッドロック例外が発生します。DbSubscriptionStorage と複数の「NumberOfWorkerThreads」を使用すると発生します。

エラー:

Could not execute command:
INSERT INTO Subscription (SubscriberEndpoint, MessageType) VALUES (@p0, @p1)
System.Data.SqlClinet.SqlException:
Transaction was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

その後、NServiceBus は切断を試みますが、まだ進行中のトランザクションがあり、UnhandledException をスローするため失敗します。

再現方法:

ここに私のApp.Configがあります:

<!-- Publishing Configuration -->
<MsmqTransportConfig InputQueue="test_publisher_output" ErrorQueue="test_error" NumberOfWorkerThreads="3" MaxRetries="5" />

<!-- Subscription Configuration -->
<UnicastBusConfig DistributorControlAddress="" DistributorDataAddress="" ForwardReceivedMessagesTo="">
    <MessageEndpointMappings>
        <add Messages="MessageAssembly" Endpoint="test_publisher_output" />
    </MessageEndpointMappings>
</UnicastBusConfig>

私のバス構成:

var bus = Configure.With()
    .Log4Net()
    .StructureMapBuilder(container)
    .XmlSerializer()
    .MsmqTransport()
        .IsTransactional(true)
        .PurgeOnStartup(false)
    .DBSubcriptionStorage(subscriptionDbProperties, true)
    .Sagas()
    .NHibernateSagaPersister(sagaDbProperties, true)
    .UnicastBus()
        .ImpersonateSender(false)
        .LoadMessageHandlers(First<GridInterceptingMessageHandler>
            .Then<SagaMessageHandler>())
    .CreateBus()
    .Start();

サブスクリプションとサガ データベースの両方の dbProperties は次のとおりです。

connection.provider      NHibernate.Connection.DriverConnectionProvider
connection.driver_class  NHibernate.Driver.SqlClientDriver
dialect                  NHibernate.Dialect.MsSql2005Dialect

NumberOfWorkerThreads を 1 より大きくしない限り、すべて正常に動作します。それよりも大きいと、上記のエラーがスローされます。

何も忘れていないことを願っています。事前にご協力いただきありがとうございます。

4

2 に答える 2

1

パブリッシュされたメッセージを同じプロセスで処理する場合は、Bus.Publish() の後に Bus.SendLocal() を実行することをお勧めします。SendLocal() メソッドはローカル キューにメッセージを配置し、内部ハンドラがそれを取得して処理します。これにより、デッドロックが解消されますが、同じセマンティクスが維持されます。

于 2010-10-15T17:12:41.207 に答える
-1

このコンポーネントの再設計を本当に検討したいと思います。nservicebusが提供する安定性が必要であり、処理の各部分が個別のメッセージハンドラーに含まれるようにコンポーネントを既に分解している場合は、各メッセージハンドラーを個別のキューを持つ個別の実行可能ファイルに配置します。それが不可能な場合は、他のコードによってロックダウンされているため、nservicebusの安定性が実際には得られていません。その場合は、必要な関数を直接呼び出す必要があります。

すべてを1つのキューで実行してテストしている場合は、テスト時にそれらを分割します。独自のメッセージをサブスクライブする理由は実際にはありません。可能であればハンドラーを個別のエンドポイントに分割し、不可能な場合は関数を直接呼び出します。

于 2010-10-25T10:55:28.753 に答える