dotnet 推薦 LightWorkFlowManager 輕量的工作過程管理庫

本文將和大家推薦我團隊開源的 LightWorkFlowManager 輕量的工作過程管理庫,適合任何需要執行工作過程的應用邏輯,可以方便將多個工作過程拼湊起來,且自動集成重試和失敗處理,以及日誌和上報功能

這個 LightWorkFlowManager 輕量的工作過程管理庫是我所在的團隊在 GitHub 上使用最友好的 MIT 協議開源的庫,請看 https://github.com/dotnet-campus/LightWorkFlowManager

這個 LightWorkFlowManager 輕量的工作過程管理庫現在已經在我團隊的正式產品應用上運行有半年了,相對來說比較穩定。使用過程中如果有任何問題,都歡迎在 GitHub 上新建 Issues 進行反饋

世界上有許多現有的工作過程管理,那爲什麼還重新造了一個?沒啥原因,自己造的用的順手。這個 LightWorkFlowManager 庫在功能上和其他的工作過程管理庫相比要缺失許多,但勝在輕量。且 LightWorkFlowManager 最重要的賣點就是對調試友好,適合用在本身複雜度就比較好的邏輯情況下,可以有效降低引入工作過程管理模塊本身帶來的額外複雜度

許多現有的功能齊全的工作過程管理庫都是在 ASP.NET Core 上使用的。然而我這裏的需求是在客戶端應用框架上使用,且大部分情況下是在用戶的設備上運行的,許多服務依賴本身是不存在的。儘管許多現有的功能齊全的工作過程管理庫都可以通過配置的形式將其切換到單機內運行,然而這樣做將在大部分時候不是庫的推薦用法,用起來沒有那麼順。爲此我所在的團隊開發了 LightWorkFlowManager 輕量的工作過程管理庫,這個庫可以很方便在客戶端框架上運行,比如在 WPF 應用程序、在 MAUI 應用程序上運行。同時 LightWorkFlowManager 也兼顧 ASP.NET Core 服務本身,特別是依賴注入部分,可以和默認的服務的依賴注入相連接

以下是 LightWorkFlowManager 輕量的工作過程管理庫的使用方法

按照 dotnet 的慣例,先安裝 NuGet 庫,請看 https://www.nuget.org/packages/dotnetCampus.LightWorkFlowManager

在開始介紹使用方法之前,需要先介紹一下 LightWorkFlowManager 裏面的概念。在 LightWorkFlowManager 裏面定義了 MessageWorkerManager 類型,將其作爲工作器的管理器,用途就是將各個工作器串聯起來,且運行起來,這個 MessageWorkerManager 就是 LightWorkFlowManager 的入口類型

在 LightWorkFlowManager 裏面定義了工作器的基礎類型就是 MessageWorker 類型,所有的業務上的開發者自定義的工作器都需要直接或間接繼承 MessageWorker 類型

瞭解基礎概念之後,接下來就開始編寫一個簡單的邏輯作爲例子

使用方法

1、 創建 MessageWorkerManager 對象。創建 MessageWorkerManager 工作器管理器即可作爲承載工作器的框架,請爲每次單獨的任務創建獨立的 MessageWorkerManager 對象

            // 每個任務一個 TaskId 號
            string taskId = Guid.NewGuid().ToString();
            // 相同類型的任務採用相同的名字,比如這是做 PPT 解析的任務
            string taskName = "PPT 解析";
            // 提供容器
            IServiceScope serviceScope = serviceProvider.CreateScope();

            var workerManager = new MessageWorkerManager(taskId, taskName, serviceScope);

2、 定義 Worker 工作器。以下例子代碼定義了模擬業務代碼的 FooWorker 工作器,可以在 FooWorker 重寫的 DoInnerAsync 方法裏面編寫執行的業務代碼。以下代碼的 InputType 和 OutputType 分別是工作器的輸入和輸出類型,每個工作器的輸出對象都會自動加入到 MessageWorkerManager 的過程上下文緩存裏面

record InputType();

record OutputType();

class FooWorker : MessageWorker<InputType, OutputType>
{
    protected override ValueTask<WorkerResult<OutputType>> DoInnerAsync(InputType input)
    {
        ...
    }
}

3、 執行 Worker 工作器。 完成類型的定義之後,接下來演示如何通過 MessageWorkerManager 將 FooWorker 運行起來

            var result = await workerManager
                .GetWorker<FooWorker>()
                .RunAsync();

以上代碼也可以簡寫爲以下代碼

            var result = await workerManager.RunWorker<FooWorker>();

以上代碼運行的前提是先注入 FooWorker 所需的 InputType 類型的對象。下文將告訴注入工作器參數部分的更多細節

機制和功能

工作器參數

工作器參數通過 MessageWorkerManager 工作器管理的 IWorkerContext 上下文讀取。每個工作器的可返回值類型都會自動被設置到 IWorkerContext 上下文裏面。如此即可自動實現上一個 Worker 的輸出作爲下一個 Worker 的輸入

在每個工作器裏面,都可以通過 SetContext 設置上下文信息

在開始執行工作器時,還可以手動設置輸入參數,如以下例子

 // 例子1:先獲取工作器,再賦值給到工作器的執行方法

            await Manager
                .GetWorker<FooWorker>()
                .RunAsync(new InputType());

 // 例子2: 通過 SetContext 進行設置參數,再執行工作器
            await Manager
                .SetContext(new InputType())
                .RunWorker<FooWorker>();

如果有些工作器之間的輸入和輸出參數需要進行轉換,也可以 SetContext 傳入轉換委託進行參數轉換

 // 以下例子將當前上下文裏的 Foo1Type 類型轉換爲 FooWorker 需要的 Foo2Type 參數
           await Manager
                .SetContext((Foo1Type foo1) => ConvertFoo1ToFoo2(foo1))
                .RunWorker<FooWorker>();

異常中斷和重試

每個 Worker 都可以返回 WorkerResult 類型的返回值,可以在返回值裏面告知框架層是否當前的 Worker 執行成功。在執行失敗時,可以賦值錯誤碼,方便定位調試或輸出。在執行失敗時,可以返回告知框架層是否需要重試

中斷後續的工作器執行有兩個方法:

方法1: 通過返回狀態爲失敗的 WorkerResult 返回值。一旦工作管理器的狀態爲 IsFail 狀態,將會阻止所有的沒有標記 CanRunWhenFail 爲 true 的工作器的執行。換句話說就是除了哪些不斷成功或失敗狀態都要執行的 Worker 工作器之外,其他的工作器都將不會執行,包括 SetContext 裏面的委託轉換也不會執行

方法2: 通過拋出異常的方式,通過 dotnet 裏面的異常可以讓後續邏輯炸掉不再執行

以上兩個方法都是框架推薦使用的。框架設計的偏好是如果在重視性能的情況下,儘量使用方法1的方式中斷執行。如果是在複雜的業務邏輯,有大量業務邏輯穿插在工作過程之外,則可以方便通過方法2進行中斷

在 Worker 裏執行其他 Worker 工作器

在一個 Worker 裏面,可以執行其他的 Worker 工作器,如此可以比較自由的實現分支邏輯,套娃決定執行工作器

例子如下:

假定有一個 Worker2 工作器,定義如下:

    class Worker2 : MessageWorker<InputType, OutputType>
    {
        protected override ValueTask<WorkerResult<OutputType>> DoInnerAsync(InputType input)
        {
            return SuccessTask(new OutputType());
        }
    }

    record InputType();

    record OutputType();

有另一個 Worker1 工作器,可以在 Worker1 裏面執行 Worker2 工作器:

    class Worker1 : MessageWorkerBase
    {
        public override async ValueTask<WorkerResult> Do(IWorkerContext context)
        {
            await Manager
                .GetWorker<Worker2>()
                .RunAsync(new InputType());

            return WorkerResult.Success();
        }
    }

委託工作器

有一些非常小且輕的邏輯,也想加入到工作過程裏面,但不想爲此定義一個單獨的工作器。可以試試委託工作器,如以下代碼例子

            var delegateMessageWorker = new DelegateMessageWorker(_ =>
            {
                // 在這裏編寫委託工作器的業務內容
            });

            var result = await messageWorkerManager.RunWorker(delegateMessageWorker);

如果連 DelegateMessageWorker 都不想創建,那也可以直接使用 MessageWorkerManager 的 RunWorker 方法傳入委託,如以下代碼例子

            await messageWorkerManager.RunWorker((IWorkerContext context) =>
            {
                // 在這裏編寫委託工作器的業務內容
            });
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章