Giter VIP home page Giter VIP logo

Comments (3)

Ralf1108 avatar Ralf1108 commented on August 18, 2024

To run the sample the following package references are required:

<ItemGroup>
	<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
	<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
	<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
	<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
	<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
	<PackageReference Include="WorkflowCore" Version="3.9.0" />
	<PackageReference Include="WorkflowCore.Persistence.Sqlite" Version="3.9.0" />
	<PackageReference Include="WorkflowCore.Persistence.SqlServer" Version="3.9.0" />
</ItemGroup>

from workflow-core.

smardine avatar smardine commented on August 18, 2024

Do you find any information about your user case ? I suspect you are correct about thé position of décide/branch step in the workflow, but i'll bé glad if you can confirm.

Describe the bug If a workflow has steps after a Decide/Branch step then it seems that steps in branch and after the branch are executed interleaved

To Reproduce Steps to reproduce the behavior: Run this program:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using WorkflowCore.Interface;
using WorkflowCore.Models;

namespace WorkflowCoreBranchProblem
{
    internal class Program
    {
        static void Main(string[] args)
        {
            File.Delete(@"mydb.db");

            var services = new ServiceCollection();
            services.AddLogging(x => x.AddConsole());
            services.AddTransient<LogStep>();
            services.AddWorkflow(x => { x.UseSqlite("Data Source=mydb.db", true); });

            var serviceProvider = services.BuildServiceProvider();
            var host = serviceProvider.GetRequiredService<IWorkflowHost>();
            host.RegisterWorkflow<TestWorkflow, TestWorkflowData>();
            host.OnStepError += Host_OnStepError;
            host.Start();

            var workflowId = host.StartWorkflow("TestWorkflow", new TestWorkflowData());
            Console.WriteLine($"Started workflow: {workflowId}");
            Console.WriteLine("Press key to exit");
            Console.ReadKey();
        }

        private static void Host_OnStepError(WorkflowInstance workflow, WorkflowStep step, Exception exception)
        {
            Console.WriteLine("Workflow Error: " + exception.Message);
        }
    }

    class TestWorkflow : IWorkflow<TestWorkflowData>
    {
        public string Id => "TestWorkflow";
        public int Version => 1;

        public void Build(IWorkflowBuilder<TestWorkflowData> builder)
        {
            var branch1 = builder.CreateBranch()
                .StartWith<LogStep>()
                .Input(x => x.Number, x => 11)
                .Then<LogStep>()
                .Input(x => x.Number, x => 12)
                .Then<LogStep>()
                .Input(x => x.Number, x => 13)
                .Then<LogStep>()
                .Input(x => x.Number, x => 14)
                .Then<LogStep>()
                .Input(x => x.Number, x => 15);

            var branch2 = builder.CreateBranch()
                .StartWith<LogStep>()
                .Input(x => x.Number, x => 21)
                .Then<LogStep>()
                .Input(x => x.Number, x => 22)
                .Then<LogStep>()
                .Input(x => x.Number, x => 23);

            builder
                .StartWith<LogStep>()
                .Input(x => x.Number, x => 1)

                .Then<LogStep>()
                .Input(x => x.Number, x => 2)
                .Output(x => x.Result, x => x.Result)

                .Decide(data => data.Result)
                .Branch((data, outcome) => data.Result == ResultType.Branch1, branch1)
                .Branch((data, outcome) => data.Result == ResultType.Branch2, branch2)

                .Then<LogStep>()
                .Input(x => x.Number, x => 4)

                .Then<LogStep>()
                .Input(x => x.Number, x => 5);
        }
    }

    class TestWorkflowData
    {
        public ResultType? Result { get; set; }
    }

    internal enum ResultType
    {
        Branch1,
        Branch2
    }

    class LogStep : IStepBody
    {
        public int Number { get; set; }

        public ResultType? Result { get; set; }

        public async Task<ExecutionResult> RunAsync(IStepExecutionContext context)
        {
            Console.WriteLine($"LogStep: {Number}");
            Result = ResultType.Branch1;
            return ExecutionResult.Next();
        }
    }
}

Output is: LogStep: 1 LogStep: 2 LogStep: 11 LogStep: 4 LogStep: 12 LogStep: 5 LogStep: 13 LogStep: 14 LogStep: 15

Expected behavior Output should be: LogStep: 1 LogStep: 2 LogStep: 11 LogStep: 12 LogStep: 13 LogStep: 14 LogStep: 15 LogStep: 4 LogStep: 5

Additional context

  • Is Decide/Branch supposed to be the last step in the workflow definition? I didn't find such information in the documentation Decision Branches
  • Are there any workarounds?

Do you find any information about your user case ? I suspect you are correct about the position of décide/branch step in the workflow, but i'll be glad if you can confirm.

from workflow-core.

Ralf1108 avatar Ralf1108 commented on August 18, 2024

I dont understand what information you need from me. Can you rephrase your question?

The only workaround I found was to split the workflow creation into multiple methods so each branch would create the full remaining workflow until the end. For small workflow this would be ok but I assume if the workflow gets bigger the could would be more complex.

In the example above it means to move the workflow after the branch into a method and call it to append it to each created branch. In a way this would duplicate code but it works correctly

from workflow-core.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.