A suitable .NET Core ultra-lightweight workflow engine: Workflow-Core

I, on the Workflow-Core

  Recent work has developed a workflow needs of their own based on object-oriented and duty chain fiddle for a small frame, and later found a lightweight workflow engine wheels on github: Workflow-Core, after reading their wiki I decided to give up before their own wheels made using this open source project to transform, and will have this blog post.

  

  Workflow-Core-based .NET Standard is a lightweight workflow engine, its GitHub address: https://github.com/danielgerlag/workflow-core , there are currently more than 1200 + a star. It provides FluentAPI, multi-tasking, persistence, and parallel processing functions, suitable for small work flow, demand for the development of the chain of responsibility.

  Since Workflow-Core support long-running workflow, so Workflow-Core support persistence of the plurality of data source format, may be implemented by installing a corresponding persistence Provider various packages:

  • (Provided by default, for testing and development) memory
  • MongoDB
  • MS SQL Server
  • MySql
  • Sqlite
  • Redis
  • PostgreSQL

  To get started immediately, Nuget install one, the latest version 2.0.0:

PM> Install-Package WorkflowCore

Second, the basic use of Workflow-Core

2.1 Hello World

  Here we created a .NET Core console application, first a quick demonstration of Workflow-Core Hello World, show you how to start a Workflow:

  (1) defines an interface implemented Workflow IWorkflow:

Copy the code
    public class HelloWorldWorkflow : IWorkflow
    {
        public string Id => "HelloWorld";

        public int Version => 1;

        public void Build(IWorkflowBuilder<object> builder)
        {
            builder
                .StartWith<HelloWorld>()
                .Then<ActiveWorld>()
                .Then<GoodbyeWorld>();
        }
    }
Copy the code

  This defines a HelloWorldWorkflow, its version number is 1, which has three steps: HelloWorld, ActiveWorld and GoodbyeWorld, will be followed by the implementation.

  (2) defined three classes inherited from Step StepBody categories:

Copy the code
    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();
        }
    }
Copy the code

  (3) ServiceCollection injected associated components Workflow-Core

Copy the code
    private static IServiceProvider ConfigureServices()
    {
        IServiceCollection services = new ServiceCollection();
        services.AddLogging(); // WorkflowCore需要用到logging service
        services.AddWorkflow();

        var serviceProvider = services.BuildServiceProvider();

        return serviceProvider;
    }
Copy the code

  (4) The method of obtaining the Main Program.cs injected into the host and execute the workflow

Copy the code
        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();
        }    
Copy the code

  Here is the incoming Workflow of Id, Workflow-Core will automatically go to match the latest version of the corresponding Workflow according to Id, results are as follows:

  

2.2 If statements

  In workflow processing, often have a lot of determination conditions, then the Workflow-Core also provides a direct function If, as shown in the following IfStatementWorkflow:

Copy the code
    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>();
        }
    }
Copy the code

  The incoming transmission MyData defined as follows:

    public class MyData
    {
        public int Counter { get; set; }
    }

  When passed in the Counter property MyData <3 or <5:00 branches have different processing logic.

2.3 MySQL persistence support

  Want workflow is configured to persistent MySQL, just follow these two steps:

  (1) mounted by MySQL Provider package Nuget:

PM> Install-Package WorkflowCore.Persistence.MySQL

  (2) into ServiceCollection

services.AddWorkflow(x => x.UseMySQL(@"Server=127.0.0.1;Database=workflow;User=root;Password=password;", true, true));

  Once started, you will find Workflow-Core automatically help you create and configure many examples of tables for persisting workflow.

  

2.4 Scheduled Tasks and cyclic tasks

  Workflow-Core also features an integrated scheduling, and cyclic tasks:

  (1) Program Tasks: a delay of 5 minutes is provided such program tasks performed in the workflow step

Copy the code
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"));
Copy the code

  (2) Cyclic task: setting such a delay of 5 minute cycle tasks in a workflow step, known Counter> 5 until the end

Copy the code
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"));
Copy the code

2.5 Saga support

  Learn distributed transaction program shoes should know Saga, the Workflow-Core also has support, which is a very useful feature:

  (1) For example: After creating a customer information, and pushed to Salesforce ERP, if an error occurs during the push, then be compensated by the retry, and the retry time interval.

Copy the code
      builder
            .StartWith<CreateCustomer>()
            .Then<PushToSalesforce>()
                .OnError(WorkflowErrorHandling.Retry, TimeSpan.FromMinutes(10))
            .Then<PushToERP>()
                .OnError(WorkflowErrorHandling.Retry, TimeSpan.FromMinutes(10));
Copy the code

  (2) Another example: When Task2 abnormal, Workflow-Core will help implement UndoTask2 and UndoTask1 help you to rewind data to restore the state.

Copy the code
builder
    .StartWith<LogStart>()
    .Saga(saga => saga
        .StartWith<Task1>()
            .CompensateWith<UndoTask1>()
        .Then<Task2>()
            .CompensateWith<UndoTask2>()
        .Then<Task3>()
            .CompensateWith<UndoTask3>()
    )
    .OnError(Models.WorkflowErrorHandling.Retry, TimeSpan.FromMinutes(10))
    .Then<LogEnd>();
Copy the code

  More Saga example, refer to: https://github.com/danielgerlag/workflow-core/tree/master/src/samples/WorkflowCore.Sample17

Third, the use in ASP.NET Core Workflow-Core in

3.1 injection and initialization

  (1) Injection: Use AddWorkflow () Extension Method

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddWorkflow();
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

  (2) Initialization:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
            .......      
            app.UseWorkflow();
    }

  Extended follows:

Copy the code
    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;
        }
    }
Copy the code

  It should be noted that: you will have to use all the Workflow Register in advance to register.

3.2 DI acquired through use  

  Where you want to use, either Controller or Service, via dependency injection to obtain Host, and use it:

Copy the code
    [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";
        }
    }
Copy the code

  Workflow these two definitions are as follows:

Copy the code
    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>();
        }
    }
Copy the code

  Examples of results is simple:

  (1)api/values

  

  (2)api/values/1

  

IV Summary

  Workflow-Core is an excellent fit .NET Core lightweight workflow engine, workflow demand for the development of small and very suitable type of chain of responsibility, can save a lot of time to avoid repeating create the wheel, the time is mainly spent on business logic above . Of course, the example demonstrated here just a few of the features in, I just selected some I used it, we are interested, then you can give a star re-examine its documentation wiki on GitHub go to their application project.

  Sample Code: https://github.com/EdisonChou/EDC.WorkflowCore.Sample

Guess you like

Origin www.cnblogs.com/xbzhu/p/11610797.html