2009-05-30 11 views
2

かかるを書くためにどのように民間、非トランザクションMSMQキューへの投稿メッセージが。 MSMQメッセージを処理してデータベースに挿入する別のWCFサービス(マルチスレッド)があります。トランザクション、マルチスレッドWCFサービス私は、WCFサービスを持っているMSMQ

私の問題はシーケンシングにあります。私はメッセージをある順序にしたい。たとえば、MSG-Aを挿入する前にMSG-Aをデータベースに移動する必要があります。だから私の現在のソリューションは非常に原油であり、データベースの観点からは高価です。

MSG-Bがあり、MSG-Aがデータベースにない場合は、メッセージキューに戻して、MSG-Aがデータベースに挿入されるまでその作業を続けます。しかし、これはテーブルスキャン(SELECT stmt)を伴うため、非常に高価な操作です。

メッセージは常に順番にキューにポストされています。

私のWCFキュー処理サービスシングルスレッドを作るのショート(サービスの動作を設定することでシングルにInstanceContextMode属性)が、誰かがよりよい解決策を提案することができますか?

おかげ

ダン

+0

に役立ちます。トランザクションであれば、メモリ内の一致するAsとBsをトラッキングするだけで何かクラッシュやタイムアウトが発生した場合にトランザクションをキューに戻すことができます。 – Bruce

答えて

1

の代わりに、すぐにメモリ内に保留中のメッセージのリストを維持し、キューからそれらを取った後、DBにメッセージをプッシュ。 AまたはBを取得したら、一致するものがリストにあるかどうかを確認します。そうであれば、データベースに正しい順序で両方を提出し、一致するものをリストから削除します。それ以外の場合は、新しいメッセージをそのリストに追加するだけです。

試合をチェックした場合は、シリアル化するタスクあまりにも高価である - 私はあなたが理由でマルチスレッドされていると仮定 - あなたは別のスレッド処理にリストを持つことができます。既存の複数のスレッドを読み込み、直ちにほとんどのメッセージをDBに提出するが、(スレッドセーフ)リストにAsとBsを入れておく。バックグラウンドスレッドは、一致するAsおよびBsを見つけるリストを清掃し、見つかったときに正しい順序でサブミットします(リストから削除します)。

一番下の行です - あなたが複数のスレッドでキューから項目を削除するので、あなたは順序を保証するために、どこかにシリアル化する必要があるとしています。トリックは、シリアルコードでロックした時間と長さを最小限に抑えることです。

また、あなたはそれがこのような状況を検出したときのエントリの順序を変更するために、トリガか何かで、データベースレベルで行うことができます何かがあるかもしれません。私はそこで助けるためにDBプログラミングについて十分に知りません。

UPDATE:メッセージに「A」というメッセージを適切な関連メッセージ「B」を関連付けることができると仮定すると、次のコードはAがBの前にデータベースに入ることを確認します。それらがデータベース内の隣接するレコードであることを確認します - AとBの間に他のメッセージが存在する可能性があります。また、何らかの理由で他のタイプの一致メッセージを受け取らずにAまたはBを取得した場合、比類のないメッセージに永遠に。

は(あなたは、単一のサブルーチンにそれらの2つの「lock'edブロックを抽出することができますが、私はAとBに関して明確にするため、このようにそれを残している)あなたがしている場合は

static private object dictionaryLock = new object(); 
static private Dictionary<int, MyMessage> receivedA = 
    new Dictionary<int, MyMessage>(); 
static private Dictionary<int, MyMessage> receivedB = 
    new Dictionary<int, MyMessage>(); 

public void MessageHandler(MyMessage message) 
{ 
    MyMessage matchingMessage = null; 
    if (IsA(message)) 
    { 
     InsertIntoDB(message); 
     lock (dictionaryLock) 
     { 
      if (receivedB.TryGetValue(message.id, out matchingMessage)) 
      { 
       receivedB.Remove(message.id); 
      } 
      else 
      { 
       receivedA.Add(message.id, message); 
      } 
     } 
     if (matchingMessage != null) 
     { 
      InsertIntoDB(matchingMessage); 
     } 
    } 
    else if (IsB(message)) 
    { 
     lock (dictionaryLock) 
     { 
      if (receivedA.TryGetValue(message.id, out matchingMessage)) 
      { 
       receivedA.Remove(message.id); 
      } 
      else 
      { 
       receivedB.Add(message.id, message); 
      } 
     } 
     if (matchingMessage != null) 
     { 
      InsertIntoDB(message); 
     } 
    } 
    else 
    { 
     // not A or B, do whatever 
    } 
} 
+0

レスポンスありがとうBruce。私が現在持っているキューは非トランザクションです。混乱させて申し訳ありません。 非常に高価になる可能性があるので、私はDBにルックアップしたいですか?私は、しかし、メモリ内でそれをシリアル化しようとしています。しかし、あなたが指摘したように、キューから引き出されたデータに複数のスレッドがアクセスしようとすると、扱いにくくなります。 私は静的辞書を考えていましたが、そのキーはメッセージを識別するために使用する一意の識別子にすることができます。あなたは辞書に関心がありますか?このリストを管理するためのよりよい方法はありますか? –

+0

4.0フレームワークのスレッドセーフ構造をチェックしてください。ベータ版での出荷が快適でない場合は、少なくとも正しい方向にポイントを与えるでしょう。 –

+0

スタティック辞書はスレッドセーフではありません。私はいくつかのサンプルコードで私の答えを更新します。 – Bruce

1

これらのキューのクライアントのみを使用すると、メッセージヘッダーとしてタイムスタンプを簡単に追加でき(IDesignサンプルを参照)、送信済みフィールド(Outlookメッセージのようなもの)もデータベースに保存できます。送信された順番で処理することができます(基本的には消費時にソートロジックを移動します)。

希望これは、タイトルは、問題の記述はキューが非トランザクションであると言いながら、キューがトランザクションであると言うので、私は少し混乱している、 エイドリアン

関連する問題