Elsa 2.0 Why is this workflow executing both the branches of a fork, when I am expecting only one?

728 Views Asked by At

Elsa is executing both the branches of the workflow, when I am expecting only one, either A or B. Here are the files for console app.

I have pushed the same here as well for your convenience.

class Program
{
    static async Task Main(string[] args)
    {
        var services = new ServiceCollection()
            .AddElsa(options => options
                .AddConsoleActivities()
                .AddActivity<ForkBranchDecisionActivity>()
                .AddWorkflow<SimpleForkWorkflow>())
            .BuildServiceProvider();

        var workflowStarter = services.GetRequiredService<IBuildsAndStartsWorkflow>();

        await workflowStarter.BuildAndStartWorkflowAsync<SimpleForkWorkflow>();
        Console.WriteLine("Done. Good bye");
    }
}

When I type 'A', the outcome will be 'A', else it will be 'B'.

public class ForkBranchDecisionActivity : Activity
{
    protected override IActivityExecutionResult OnExecute()
    {
        Console.WriteLine("Choose a branch. A or B");
        Console.WriteLine("Typing a will resulting in going through branch A");
        Console.WriteLine("Any other key will result in branch B");
        var userChoosenBranch = Console.ReadLine();

        if (userChoosenBranch!.ToUpper() == "A")
            return Outcome("A");
        
        return Outcome("B");
    }
}

Is the branch chosen not based on the outcome of the previous activity? If not then what determines the branch to be executed? How come both branches are executed in my case?

public class SimpleForkWorkflow : IWorkflow
{
    public void Build(IWorkflowBuilder builder)
    {
        builder
            .WriteLine("This demonistrates a simple workflow with fork .")
            .WriteLine("Using forks we can branch a workflow.")
            .Then<ForkBranchDecisionActivity>()
            .Then<Fork>(
                fork => fork.WithBranches("A", "B"),
                fork =>
                {
                    var aBranch = fork
                        .When("A")
                        .WriteLine("You are in A branch. First line")
                        .WriteLine("You are in A branch. Second line.")
                        .ThenNamed("AfterJoin");

                    var bBranch = fork
                        .When("B")
                        .WriteLine("You are in B branch. First line")
                        .WriteLine("You are in B branch. Second line.")
                        .ThenNamed("AfterJoin");
                })
            .WithName("AB Fork")
            .Add<Join>(x => x.WithMode(Join.JoinMode.WaitAny)).WithName("AfterJoin")
            .WriteLine("Workflow finished.");
    }
}

My final console output looks as follows.

This demonistrates a simple workflow with fork .
Using forks we can branch a workflow.
Choose a branch. A or B
Typing a will resulting in going through branch A
Any other key will result in branch B
a
You are in B branch. First line
You are in B branch. Second line.
Workflow finished.
You are in A branch. First line
You are in A branch. Second line.
Workflow finished.
Done. Good bye

Update

Thanks @Sipke Schoorstra. Its not obvious from the first glance. So highlighting here the changes.

Instead of

        .Then<ForkBranchDecisionActivity>()
        .Then<Fork>( 

it should be

        .Then<ForkBranchDecisionActivity>(fork =>
        {
            fork.When("A")

Note Fork activity is totally removed and is no longer the part of workflow.

1

There are 1 best solutions below

0
On BEST ANSWER

This is by design: the Fork activity will schedule all branches. It is a way to split workflow execution into multiple branches.

This allows you to do things like waiting for some user input in one branch, but continue with another branch after some timeout event. A good example of this scenario is described here.

To implement your workflow, all you need is this:

public class SimpleForkWorkflow : IWorkflow
{
    public void Build(IWorkflowBuilder builder)
    {
        builder
            .WriteLine("This demonstrates a simple workflow with switch.")
            .WriteLine("Using switch we can branch a workflow.")
            .Then<ForkBranchDecisionActivity>(fork =>
            {
                fork.When("A")
                    .WriteLine("You are in A branch. First line")
                    .WriteLine("You are in A branch. Second line.")
                    .ThenNamed("Finish");

                fork.When("B")
                    .WriteLine("You are in B branch. First line")
                    .WriteLine("You are in B branch. Second line.")
                    .ThenNamed("Finish");
                
            })
            .WriteLine("Workflow finished.").WithName("Finish");
    }
}

Notice that the Then<ForkBranchDecisionActivity> call accepts a parameter that allows you to connect arbitrary outcomes to your activity ("A" and "B" in your case).

When you run this workflow, the outcome will be as expected:

This demonstrates a simple workflow with switch.
Using switch we can branch a workflow.
Choose a branch. A or B
Typing 'a' will result in going through branch A
Any other key will result in branch B
a
You are in A branch. First line
You are in A branch. Second line.
Workflow finished.