3

単なる疑似コードであるため、CodeReview.Stackexchange から転載

タスク プロセッサのワーカー ロールを構築しています。タスクは単純な DB テーブル (Guid、Json 文字列、ステータス) に挿入され、Guid は Azure メッセージ キューにプッシュされます。worker ロールはキューからメッセージをポップし、DB から JSON 命令を取得してそのタスクを処理します。

冪等性と再試行のすべてのコーナーケースを確実にカバーし、次の擬似コードを作成しようとしています。

私の主な問題は、「ProcessTask」フェーズが非トランザクション (外部サービスへの HTTP 投稿とサービス呼び出し) であり、繰り返し呼び出しが悪い (Mkay) ことです。

誰かがこれを再確認して、私が特定していないコーナーケースがあるかどうかを確認できますか.

次の情報を持つタスクがデータベースに存在すると仮定します。

| Id   | TaskInstruction       | Status  | PopReceipt | 
+------+-----------------------+---------+------------+
| GUID | { ... some json ... } | Pending | NULL       |

次の疑似コードは、次の状況をカバーしています。

  1. ワーカーはメッセージを取得し、時間内に処理し、データベースを更新してメッセージを削除します。
  2. #1 以外は、30 秒の非表示タイムアウトよりも長くかかりますが、それでも成功します。
  3. メッセージの処理に失敗したため、再試行する必要があります。
  4. メッセージの処理に何度も失敗し、許可されている最大デキュー カウントを超えています。

計画では、Azure BlobStorage の AquireLease メカニズムを使用して、冪等性の理由から重要なコードの周りでファイル ロックとして使用する予定です。

疑似コード

BlobAquireLease                                  //LOCK Only Worker Role Can Retrieve at a time
    var message = Queue.GetMessage(30);          // 30 second invisibility timeout
    var dbTask = DBSession.GetTask(message.Id);  //Retrieve the DB Entry
    If dbTask.Status != Pending OR Retrying
        //Crap another role is processing this task but has 
        //overshot the 30 second timeout and now my popreceipt 
        //supercedes his - put my popreceit in the DB, and do nothing more
        DBSession.UpdateTask(message.Id, newPopReceipt) // put the new pop receipt in the db
        BlobReleaseLease                                //Release the LOCK
        return;                                         //Get out of here
    EndIf

    //Otherwise, I'm ok to handle this task.
    DBSession.UpdateTask(message.Id, Status.Processing);
BlobReleaseLock

//At this point, the task is mine, and I've got 30 seconds to do stuff

TRY
    ProcessTask(dbtask);
    //Successful
    BlobAquireLease                                                //Grab the LOCK Again
        //Get from DB Again just incase I've 
        //over shot the 30 seconds and someone else has updated the popreceipt
        var dbTaskRefreshed = DBSession.GetTask(message.Id); 
        DBSession.UpdateTask(message.Id, Status.SUCCESS);          //Update the status in the DB
        Queue.DeleteMessage(message, dbTaskRefreshed.PopReceipt);  //Delete the message
    BlobReleaseLease
ENDTRY
CATCH
    //An Error Occured and the task couldn't be processed. 
    //need to update the database
    BlobAcquireLease                                               //Grab the LOCK again

        IF message.DequeueCount > MAX ALLOWED                      //Too many Attempts
            //Get from DB Again just incase I've 
            //over shot the 30 seconds and someone else has updated the popreceipt
            var dbTaskRefreshed = DBSession.GetTask(message.Id); 
            DBSession.UpdateTask(message.Id, Status.FAILED);
            Queue.DeleteMessage(message, dbTaskRefreshed.PopReceipt)
        ELSE
            //Haven't reached the max dequeue count yet, so just 
            //let the invisibility timeout elapse on it's own and someone will retry
            DBSession.UpdateTask(message.Id, Status.RETRYING);
        END IF
    BlobReleaseLease
ENDCATCH
4

0 に答える 0