簡體   English   中英

使用 NServicebus saga 序列化長時間運行的端點處理程序的執行

[英]Using a NServicebus saga to serialize execution of long-running endpoint handlers

我們正在嘗試使用 Saga 序列化業務對象列表的處理。

現在,沒有 Saga,我們只需循環遍歷對象列表,然后觸發bus.Send(new ProcessBusinessObejct(obj))異步以讓處理程序執行。 所以處理或多或少是並行發生的,取決於這個設置,我相信:

endpointConfiguration.LimitMessageProcessingConcurrencyTo( 4 );

這工作正常,但並發處理程序的數量現在在數據庫上很難。

串聯觸發這些處理程序是可以的,即僅當當前進程完成(失敗或成功)時才繼續下一個。 我們不想將並發設置為 1,它會影響端點中的所有處理程序。

這個想法是使用 Scatter/Gather 模式和 Saga 來跟蹤對象的數量並使用 a 計數(總計數、失敗計數、成功計數)更新狀態機,最后在列表為完成/空。

問題是

A)我不確定如何跟蹤傳奇中的列表。 SagaData 需要一個 List 來保存所有對象嗎? 然后在處理程序發出它已完成處理的信號時刪除一個實例。 傳奇不支持分層數據,因此沒有列表或列表。 我相信在 NSB v7 中仍然如此。

和 B) 使用 saga 是否可行或矯枉過正,還是有更簡單的方法來實現這一目標?

我們正在使用 Sql Server 持久性和傳輸以及 NSB 7。

非常感謝任何輸入!

我認為你正在尋找這樣做。 請注意,根據您使用的持久層,您可能需要將實際導入與更新 saga 狀態分開。 我在這里寫了關於這個的博客。

Saga 數據也可以存儲一個列表,但我認為在大多數情況下你可以擺脫計數。 另一個重要的注意事項(盡管應該很明顯)是,如果消息無法處理並進入錯誤隊列(例如,ImportData 中未捕獲的異常),則整個 saga 將保持不完整,直到該消息被重試和處理。

public class MySaga : Saga<MySagaData>
   : IAmStartedByMessages<StartTheProcess>,
     IHandleMessages<ImportData>,
     IHandleMessages<ImportFinished>
{
    public async Task Handle(StartTheProcess message, IMessageHandlerContext context)
    {
        Data.ObjectsToImport = message.ObjectCount;
        Data.JobID = Guid.NewGuid(); //To generate a correlation ID to connect future messages back to this saga instance

        foreach(var id in message.ObjectIdsToImport)
        {
            await context.SendLocal(new ImportData
            {
                JobID = Data.JobID //You need this to correlate messages back to the saga
                //Anything else you need to pass on to ImportData
                ObjectIdToImport = id
            }
        });
    }

    public async Task Handle(ImportData message, IMessageHandlerContext context)
    {
        //import the data and increment the counter
        var result = ImportData(message.ObjectIdToImport);
        if(result == Result.Success)
        {
            Data.SuccessImport++;
        }
        else
        {
            Data.FailedImport++;
        }

        await CheckIfFinished(context);
    }

    public async Task Handle(ImportFinished message, IMessageHandlerContext context)
    {
        //do any post cleanups or Mark as complete 
        MarkAsComplete();
        return Task.CompletedTask;
    }

    private async Task CheckIfFinished(IMessageHandlerContext context)
    {
        if(Data.SuccessImport + Data.FailedImport == Data.ObjectsToImport)
        {
            //Everything is done
            context.SendLocal(new ImportFinished { JobID = Data.JobID });
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM