elsa-core icon indicating copy to clipboard operation
elsa-core copied to clipboard

[BUG] Context.SetVariable not stored in WorkflowInstance

Open Sverre-W opened this issue 1 year ago • 2 comments

Description

When using the Context.SetVariable the variable is not stored after the workflow was suspended. The storage provider is the WorkflowStorageDriver.

Steps to Reproduce

Using the following snippet to reproduce


public class CreateVariableActivity : CodeActivity
{
    protected override void Execute(ActivityExecutionContext context)
    {
        var variable = context.SetVariable("Foo", "Bar");
        Console.Write(variable.StorageDriverType);
    }
}

public class ReadVariableActivity : CodeActivity<string>
{
    protected override void Execute(ActivityExecutionContext context)
    {
        var foo = context.GetVariable<string>("Foo");
        Result.Set(context, foo);
    }
}

class SampleWorkflow : WorkflowBase
{
    protected override void Build(IWorkflowBuilder workflow)
    {
        var variable1 = new Variable<string>();

        workflow.Root = new Sequence
        {
            Variables =
            {
                variable1
            },

            Activities =
            {
                new CreateVariableActivity(),
                new Delay(TimeSpan.FromSeconds(5)),
                new ReadVariableActivity
                {
                    Result = new(variable1)
                },
                new WriteLine(variable1)
            }
        };
    }
}

Expected Behavior

For the variable to return "Bar"

Actual Behavior

The variable is null

Screenshots

Variable Storage Provider

image

Variable is null

image

Sverre-W avatar Jun 24 '24 09:06 Sverre-W

Based on the information provided, it seems that the issue you're experiencing is related to the persistence of variables across the suspension and resumption of a workflow in Elsa. When a workflow is suspended and later resumed, any variables stored in memory will be lost unless they are persisted using a storage provider that retains the data beyond the workflow's in-memory lifetime.

In the code snippet you provided, you're using context.SetVariable("Foo", "Bar") to set a variable within the CreateVariableActivity. However, if the workflow is suspended after this activity, for example, during the Delay activity, and then resumed, the variable "Foo" may not be available unless it's persisted using a storage provider that supports persistence across suspensions.

To ensure that variables are persisted across workflow suspensions, you should use a storage provider that saves the data to a persistent store. The default WorkflowStorageDriver should handle this, as it is designed to persist variables with the workflow instance.

Make sure that the WorkflowStorageDriver is properly configured in your application. If it's not configured or if there's a misconfiguration, that could explain why the variable is not being persisted.

If you are still facing issues, you might want to check the following:

  1. Ensure that the variable type is serializable.
  2. Verify that the storage provider is registered and configured correctly in your application startup.
  3. Check for any exceptions or errors in the logs that might indicate a problem with variable persistence.

If you have followed all the steps and the issue persists, it might be a bug or a missing feature in the version of Elsa you are using. In such a case, consider reaching out to the Elsa community or checking the GitHub issues for similar reports.

This comment was generated by Glime.

glime-ai[bot] avatar Jun 24 '24 09:06 glime-ai[bot]

I encountered the same bug. I have a custom activity to create a bookmark. When I used WorkflowRuntime.ResumeWorkflowsAsync to resume the suspended workflow, the workflow lost all of its variables. Did I miss setting something?

feidon avatar Jul 03 '24 06:07 feidon

Same problem as described above.

oyvindlu avatar Jul 09 '24 11:07 oyvindlu

I adapted the code as followed but still have the same issue, the only difference is the variable now reads the default empty value



public class CreateVariableActivity : CodeActivity
{
    protected override void Execute(ActivityExecutionContext context)
    {
        var variable = context.SetVariable("Foo", "Bar");
        Console.Write(variable.StorageDriverType);
    }
}

public class ReadVariableActivity : CodeActivity<string>
{
    protected override void Execute(ActivityExecutionContext context)
    {
        var variables =  context.WorkflowExecutionContext.Variables;
        var foo = context.GetVariable<string>("Foo");
        Result.Set(context, foo);
    }
}

class SampleWorkflow : WorkflowBase
{
    protected override void Build(IWorkflowBuilder workflow)
    {
        var variable1 = new Variable<string>("Foo", "");
        
        workflow.Variables =
        [
            variable1
        ];

        workflow.Root = new Sequence
        {
            Activities =
            {
                new CreateVariableActivity(),
                new Delay(TimeSpan.FromSeconds(5)),
                new ReadVariableActivity
                {
                    Result = new(variable1)
                },
                new WriteLine(variable1)
            }
        };
    }
}

I also noticed that the WorkflowStorageDriver is deprecated so maybe we need to do something different?

Sverre-W avatar Sep 26 '24 04:09 Sverre-W

Make sure to configure your variable with a storage driver that persists the value. There are different drivers, the most common one being the WorkflowStorageDriver (deprecated with 3.3-preview and beyond in favor of WorkflowInstanceStorageDriver).

Note that the storage drivers are applied only to variables defined on the workflow definition directly. This means that if you have a custom activity that declares a variable, its storage driver will not be invoked. This is a current limitation that should be lifted in a future update.

Here's an example of defining variables with a persistent storage driver:

public class SampleWorkflow : WorkflowBase
{
    protected override void Build(IWorkflowBuilder workflow)
    {
        // The WithVariable method ensures that the created variable will be added to the Workflow's Variables collection, which is required for persistent variables.
        var variable1 = workflow.WithVariable<string>("Foo").WithWorkflowStorage();
        
        workflow.Variables =
        [
            variable1
        ];

        workflow.Root = new Sequence
        {
            Activities =
            {
                new StartAt(DateTimeOffset.UtcNow + TimeSpan.FromSeconds(5))
                {
                    CanStartWorkflow = true
                },
                new WriteLine(variable1),
                new SetVariable
                {
                    Variable = variable1,
                    Value = new (Literal.From("Bar"))
                },
                new Delay(TimeSpan.FromSeconds(1)),
                new WriteLine(variable1)
            }
        };
    }
}

Output will be as expected:

2024-09-26_19-26-21

sfmskywalker avatar Sep 26 '24 17:09 sfmskywalker

Thanks!

Sverre-W avatar Sep 27 '24 03:09 Sverre-W