一个超轻量级工作流引擎:Workflow-Core
近期工作上有一個工作流的開發需求,自己基于面向對象和職責鏈模式搗鼓了一套小框架,后來在github上發現一個輕量級的工作流引擎輪子:Workflow-Core,看完其wiki之后決定放棄之前自己造的輪子,使用這個開源項目來改造,也就有了這一篇博文。
01
—
關于Workflow-Core
????????
Workflow-Core是一個基于.NET Standard的輕量級工作流引擎,其GitHub地址為:https://github.com/danielgerlag/workflow-core,目前有超過1200+個star。它提供了FluentAPI、多任務、持久化以及并行處理的功能,適合于小型工作流、責任鏈的需求開發。
由于Workflow-Core支持工作流長期運行,因此Workflow-Core支持以下多種數據源格式的持久化,可以通過安裝不同的Provider包來實現對應的持久化:
內存(默認提供,用于測試和開發)
MongoDB
MS SQL Server
MySql
Sqlite
Redis
PostgreSQL
立刻上手把,Nuget上安裝一把,目前最新版本2.0.0:
PM> Install-Package WorkflowCore02
—
Workflow-Core 基礎使用
1、Hello World
這里創建了一個.NET Core控制臺應用程序,快速演示第一個Workflow-Core的Hello World,展示如何開始一個Workflow:
(1)定義一個實現IWorkflow接口的Workflow:
這里定義了一個HelloWorldWorkflow,其版本號為1,它有3個步驟:HelloWorld、ActiveWorld和GoodbyeWorld,會依次執行。
(2)定義三個繼承自StepBody類的步驟類:
public class HelloWorld : StepBody { public override ExecutionResult Run(IStepExecutionContext context) { Console.WriteLine("Hello World!"); return ExecutionResult.Next(); } } public class ActiveWorld : StepBody { public override ExecutionResult Run(IStepExecutionContext context) { Console.WriteLine("I am activing in the World!"); return ExecutionResult.Next(); } } public class GoodbyeWorld : StepBody { public override ExecutionResult Run(IStepExecutionContext context) { Console.WriteLine("Goodbye World!"); return ExecutionResult.Next(); } } (3)ServiceCollection中注入Workflow-Core相關組件 private static IServiceProvider ConfigureServices() { IServiceCollection services = new ServiceCollection(); services.AddLogging(); // WorkflowCore需要用到logging service services.AddWorkflow(); var serviceProvider = services.BuildServiceProvider(); return serviceProvider; }(4)在Program.cs的Main方法中獲取到注入的host并執行工作流
public static void Main(string[] args) { var serviceProvider = ConfigureServices(); var host = serviceProvider.GetService<IWorkflowHost>(); host.RegisterWorkflow<HelloWorldWorkflow>(); host.Start(); // Demo1:Hello World host.StartWorkflow("HelloWorld"); Console.ReadKey(); host.Stop(); }這里傳入的是Workflow的Id,Workflow-Core會根據Id去自動匹配最新版本的對應Workflow,運行結果如下:
2、無處不在的If
????????在工作流處理中,往往會有很多的條件判斷,那么在Workflow-Core中也提供了直接的If功能,如下面這個IfStatementWorkflow所示:
public class IfStatementWorkflow : IWorkflow<MyData> { public string Id => "if-sample"; public int Version => 1; public void Build(IWorkflowBuilder<MyData> builder) { builder .StartWith<SayHello>() .If(data => data.Counter < 3).Do(then => then .StartWith<PrintMessage>() .Input(step => step.Message, data => "Outcome is less than 3") ) .If(data => data.Counter < 5).Do(then => then .StartWith<PrintMessage>() .Input(step => step.Message, data => "Outcome is less than 5") ) .Then<SayGoodbye>(); } }這個傳遞進來的MyData的定義如下:
public class MyData { public int Counter { get; set; } }當傳遞進來的MyData的Counter屬性<3 或 <5時會有不同的分支進行邏輯的處理。
3、MySQL持久化支持
????????想要將工作流配置持久化到MySQL,只需以下兩步:
(1)通過Nuget安裝MySQL Provider包:
PM> Install-Package WorkflowCore.Persistence.MySQL(2)注入到ServiceCollection
services.AddWorkflow(x => x.UseMySQL(@"Server=127.0.0.1;Database=workflow;User=root;Password=password;", true, true));一旦啟動,你就會發現Workflow-Core自動幫你創建了很多表用于持久化工作流配置和實例。
4、計劃任務和循環任務
????????Workflow-Core還繼承了計劃任務和循環任務的功能:
(1)計劃任務:比如在工作流步驟中設置一個延遲5分鐘執行的計劃任務
builder .StartWith(context => Console.WriteLine("Hello")) .Schedule(data => TimeSpan.FromSeconds(5)).Do(schedule => schedule .StartWith(context => Console.WriteLine("Doing scheduled tasks")) ) .Then(context => Console.WriteLine("Doing normal tasks"));(2)循環任務:比如在工作流步驟中設置一個延遲5分鐘進行的循環任務,知道Counter > 5才結束
builder .StartWith(context => Console.WriteLine("Hello")) .Recur(data => TimeSpan.FromSeconds(5), data => data.Counter > 5).Do(recur => recur .StartWith(context => Console.WriteLine("Doing recurring task")) ) .Then(context => Console.WriteLine("Carry on"));5、Saga支持
????????了解分布式事務方案的童鞋應該都知道Saga,在Workflow-Core中也有支持,這是一個十分有用的功能:
(1)比如:在創建一個客戶信息之后,將其推送到Salesforce和ERP,如果推送過程中發生了錯誤,那么就通過重試進行補償,并且重試有時間間隔。
(2)又比如:當Task2發生異常時,Workflow-Core會幫助執行UndoTask2 和 UndoTask1 幫你回滾數據以恢復狀態。
更多Saga示例,請參考:https://github.com/danielgerlag/workflow-core/tree/master/src/samples/WorkflowCore.Sample17
03
—
ASP.NET Core中使用Workflow-Core
1、注入與初始化
????????(1)注入:使用AddWorkflow()擴展方法
public void ConfigureServices(IServiceCollection services) { services.AddWorkflow(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }(2)初始化:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ....... app.UseWorkflow(); }擴展方法如下:
public static class ConfigureExtensions { public static IApplicationBuilder UseWorkflow(this IApplicationBuilder app) { var host = app.ApplicationServices.GetService<IWorkflowHost>(); host.RegisterWorkflow<EdcWorkflow>(); host.RegisterWorkflow<EdcDataWorkflow, EdcData>(); host.Start(); var appLifetime = app.ApplicationServices.GetService<IApplicationLifetime>(); appLifetime.ApplicationStopping.Register(() => { host.Stop(); }); return app; } }這里需要注意的就是:將你要用到的所有Workflow都事先進行Register注冊。
????????在你想要用到的地方,無論是Controller還是Service,通過依賴注入獲取到Host,并使用它:
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private IWorkflowController _workflowService; public ValuesController(IWorkflowController workflowService) { _workflowService = workflowService; } // GET api/values [HttpGet] public async Task<IEnumerable<string>> Get() { await _workflowService.StartWorkflow("EdcWorkflow"); return new string[] { "EdcWorkflow v1" }; } // GET api/values/5 [HttpGet("{id}")] public async Task<string> Get(int id) { await _workflowService.StartWorkflow("EdcDataWorkflow", new EdcData() { Id = id }); return "EdcDataWorkflow v1"; } }這兩個Workflow的定義如下:
public class EdcWorkflow : IWorkflow { public string Id => "EdcWorkflow"; public int Version => 1; public void Build(IWorkflowBuilder<object> builder) { builder .StartWith<HelloWorld>() .Then<GoodbyeWorld>(); } } public class EdcDataWorkflow : IWorkflow<EdcData> { public string Id => "EdcDataWorkflow"; public int Version => 1; public void Build(IWorkflowBuilder<EdcData> builder) { builder .StartWith<HelloWorld>() .If(data => data.Id < 3).Do(then => then .StartWith<PrintMessage>() .Input(step => step.Message, data => "Passed Id is less than 3") ) .If(data => data.Id < 5).Do(then => then .StartWith<PrintMessage>() .Input(step => step.Message, data => "Passed Id is less than 5") ) .Then<GoodbyeWorld>(); } }示例結果很簡單:
(1)api/values
(2)api/values/1
04
—
小結
Workflow-Core是一個適合.NET Core的優秀的輕量級工作流引擎,對于小型工作流和責任鏈類型的需求開發很適合,可以節約大量時間避免重復造輪子,將時間主要花在業務邏輯上面。當然,這里演示的示例只是眾多功能特性中的一小部分,我只是選取了我用到的部分而已,大家有興趣的話可以去GitHub上先給個star再仔細研究其wiki文檔,應用到自己的項目中去。
恰童鞋騷年,風華不再正茂,仍想揮斥方遒
點個在看少個bug??
總結
以上是生活随笔為你收集整理的一个超轻量级工作流引擎:Workflow-Core的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 译 | 宣布ML.NET 1.2 及模型
- 下一篇: ASP.NET Core 3.0中支持A