Click or drag to resize

WorkflowNewChildWorkflowFutureStubTWorkflowInterface Method

Creates a specialized stub suitable for starting and running a child workflow in parallel with other workflow operations such as child workflows or activities.

Namespace:  Neon.Cadence
Assembly:  Neon.Cadence (in Neon.Cadence.dll) Version: 2.14.0
Syntax
public ChildWorkflowStub<TWorkflowInterface> NewChildWorkflowFutureStub<TWorkflowInterface>(
	string methodName = null,
	ChildWorkflowOptions options = null
)
where TWorkflowInterface : class

Parameters

methodName (Optional)
Type: SystemString
Optionally identifies the target workflow method. This is the name specified in [WorkflowMethod] attribute for the workflow method or null/empty for the default workflow method.
options (Optional)
Type: Neon.CadenceChildWorkflowOptions
Optionally specifies custom ChildWorkflowOptions.

Type Parameters

TWorkflowInterface
The target workflow interface.

Return Value

Type: ChildWorkflowStubTWorkflowInterface
A ChildWorkflowStubTWorkflowInterface instance.
Exceptions
ExceptionCondition
ObjectDisposedExceptionThrown if the associated Cadence client is disposed.
NotSupportedExceptionThrown when this is called outside of a workflow entry point method.
Remarks

Sometimes workflows need to run child workflows in parallel with other child workflows or activities. Although the typed workflow stubs return a Task or TaskTResult, workflow developers are required to immediately await every call to these stubs to ensure that the workflow will execute consistently when replayed from history. This means that you must not do something like this:

C#
public interface IMyWorkflow : IWorkflow
{
    [WorkflowMethod]
    Task MainAsync();

    [WorkflowMethod(Name = "child")]
    Task<string> ChildAsync(string arg);
}

public class MyWorkflow : WorkflowBase, IMyWorkflow
{
    public Task MainAsync()
    {
        var stub1     = Workflow.NewChildWorkflowStub<IMyWorkflow>("FOO");
        var childTask = stub1.DoChildWorkflow();
        var stub2     = Workflow.NewChildWorkflowStub<IMyWorkflow>();
        var value2    = await stub2.DoChildWorkflow("BAR");
        var value1    = await childTask;
    }

    public Task<string> ChildAsync(string arg)
    {
        return await Task.FromResult(arg);
    }
}

The MainAsync() workflow method here creates and starts a child workflow, but it doesn't immediately await it. It then runs another child workflow in parallel and then after the second child returns, the workflow awaits the first child. This pattern is not supported by Neon.Cadence because all workflow related operations need to be immediately awaited to ensure that operations will complete in a consistent order when workflows are replayed.

Note Note
The reason for this restriction is related to how the current Neon.Cadence implementation uses an embedded GOLANG Cadence client to actually communicate with a Cadence cluster. This may be relaxed in the future if/when we implement native support for the Cadence protocol.

A correct implementation would look something like this:

C#
public interface IMyWorkflow : IWorkflow
{
    [WorkflowMethod]
    Task MainAsync();

    [WorkflowMethod(Name = "child")]
    Task<string> ChildAsync(string arg);
}

public class MyWorkflow : WorkflowBase, IMyWorkflow
{
    public Task MainAsync()
    {
        var stub1  = Workflow.NewChildWorkflowFutureStub<IMyWorkflow>("child");
        var future = await stub1.StartAsync$lt;string>("FOO");   // Starting the child with param: "FOO"
        var stub2  = Workflow.NewChildWorkflowStub<IMyWorkflow>();
        var value2 = await stub2.DoChildWorkflow("BAR");            // This returns: "BAR"
        var value1 = await future.GetAsync();                       // This returns: "FOO"
    }

    public Task<string> ChildAsync(string arg)
    {
        return await Task.FromResult(arg);
    }
}

Here we call NewChildWorkflowFutureStubTWorkflowInterface(String, ChildWorkflowOptions) specifying "child" as the workflow method name. This matches the [WorkflowMethod(Name = "child")] attribute decorating the ChildAsync() workflow interface method. Then we start the child workflow by awaiting StartAsync(Object). This returns an ChildWorkflowFutureTResult whose GetAsync method returns the workflow result. The code above calls this to retrieve the result from the first child after executing the second child in parallel.

Note Note

You must take care to pass parameters that match the target method. Neon.Cadence does check these at runtime, but there is no compile-time checking.

You'll also need to cast the GetAsync result to the actual type (if required). This method always returns the object type even if referenced workflow and activity methods return void. GetAsync will return null in these cases.

See Also