2017-02-23 5 views
0

私のエンドポイントがIDを受け付け、結果を構成するために重い操作を実行する(PDFを生成する)APIを開発しています。リクエストの作業をキューに入れ、同じ作業を1回だけ実行する方法

短いリソースで同じリソースに対して同じリクエストを複数回取得する可能性があります。そのため、IDを追跡する作業キューが必要です。最初のリクエストは実際の作業を開始し、次の要求は(最初にパイプラインに入っているかどうかを最初に確認します)、作業が完了して同じ結果が返されるまで待ってください。

最初に私はConcurrentDictionaryが役に立つと思ったが、の作業が完了するまでの処理方法を知りませんでした。私もObservableCollectionを見ましたが、私はその安全性についてはわかりません(手動で安全にすることに多大な努力を払わずに)。

答えて

0

私はたぶんそれの周りにロックを持つ通常の辞書を使用し、Taskの内部には、作業項目の結果が計算されると完了します。

つまり、作業の各部分を実行することは、Task<WorkResult>として表されます。

新しい要求があなたに来る場合のような何かを行うことができます:今、辞書から項目を削除し、誰に残っ質問があります

lock (currentWork) 
{ 
    Task<WorkResult> workItem = null; 
    if (currentWork.TryGetResult(workId, out workItem)) 
    { 
    // Work is already in progress. Reuse that work item 
    return workItem; // The caller can await that 
    } 

    // Create a new workItem 
    workItem = FunctionThatStartsWork(); // Could also be a Task.Run(...) thing 
    // Store it in the map 
    currentWork[workId] = workItem; 

    // Return it to the caller so that he can await it 
    return workItem; 
} 

。 1つのアプローチは、完了後にマップから削除する作業タスクの作成を継続することです。

workItem.ContinueWith(wi => { 
    lock (currentWork) { 
    currentWork.Remove(workId); 
    } 
}); 
+0

ああ基本的に私は辞書にタスクを保存していますが、IDがまだ存在しない場合は、そのタスクに 'ID'を追加します。同じIDの後続要求では、タスクを取り出して'彼ら? – romeozor

+0

はい、それです。あなたは '.Wait()'や '.Result'をブロックすることもできますが、async/awaitが利用可能で、スレッド全体をブロックしたくないと思います。 – Matthias247

2

これを拡大縮小したい場合は、メッセージキュー(RabbitMQなど)を使用して代替アーキテクチャーをお勧めします。 APIは単にメッセージをキューに公開するだけで、メッセージを消費して処理するWindowsサービスを持つことができます。 2つのアプリケーションはもちろん、情報を同期させるために共通のデータストアを共有することができます。

関連する問題