Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ private async ValueTask ProcessChildCompletedAsync(ActivityExecutionContext flow
return;
}

// Check if the completed activity is a direct child of this flowchart.
// If not, skip flowchart-specific processing as the activity is managed by an intermediate container (e.g., sub-process).
if (!IsDirectChild(flowchartContext, completedActivityContext))
{
// The activity is not a direct child, so we don't process its outbound connections.
// Instead, just check if the flowchart should complete.
await CompleteIfNoPendingWorkAsync(flowchartContext);
return;
}

// Schedule the outbound activities
var flowGraph = GetFlowGraph(flowchartContext);
var flowScope = GetFlowScope(flowchartContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,27 @@ private async ValueTask OnChildCompletedTokenBasedLogicAsync(ActivityCompletedCo
{
var flowContext = ctx.TargetContext;
var completedActivity = ctx.ChildContext.Activity;
var completedActivityContext = ctx.ChildContext;
var flowGraph = flowContext.GetFlowGraph();
var tokens = GetTokenList(flowContext);

// If the completed activity is a terminal node, complete the flowchart immediately.
if (completedActivity is ITerminalNode)
{
tokens.Clear();
await flowContext.CompleteActivityAsync();
await ClearTokensAndCompleteFlowchartAsync(flowContext, tokens);
return;
}

// Check if the completed activity is a direct child of this flowchart.
// If not, skip flowchart-specific processing as the activity is managed by an intermediate container (e.g., sub-process).
if (!IsDirectChild(flowContext, completedActivityContext))
{
// The activity is not a direct child, so we don't process its tokens.
// Instead, just check if the flowchart should complete.
if (!flowContext.HasPendingWork())
{
await ClearTokensAndCompleteFlowchartAsync(flowContext, tokens);
}
return;
}

Expand Down Expand Up @@ -151,14 +164,22 @@ private async ValueTask OnChildCompletedTokenBasedLogicAsync(ActivityCompletedCo
// Complete flowchart if no pending work.
if (!flowContext.HasPendingWork())
{
tokens.Clear();
await flowContext.CompleteActivityAsync();
await ClearTokensAndCompleteFlowchartAsync(flowContext, tokens);
}

// Purge consumed tokens for the completed activity.
tokens.RemoveWhere(t => t.ToActivityId == completedActivity.Id && t.Consumed);
}

/// <summary>
/// Clears all tokens and completes the flowchart.
/// </summary>
private static async ValueTask ClearTokensAndCompleteFlowchartAsync(ActivityExecutionContext flowContext, List<Token> tokens)
{
tokens.Clear();
await flowContext.CompleteActivityAsync();
}

private async ValueTask OnTokenFlowActivityCanceledAsync(CancelSignal signal, SignalContext context)
{
var flowchartContext = context.ReceiverActivityExecutionContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,17 @@ private async Task CompleteIfNoPendingWorkAsync(ActivityExecutionContext context
}
}

/// <summary>
/// Checks if the completed activity is a direct child of the flowchart.
/// </summary>
/// <param name="flowchartContext">The flowchart's execution context.</param>
/// <param name="completedActivityContext">The completed activity's execution context.</param>
/// <returns>True if the activity is a direct child; otherwise, false.</returns>
private static bool IsDirectChild(ActivityExecutionContext flowchartContext, ActivityExecutionContext completedActivityContext)
{
return completedActivityContext.ParentActivityExecutionContext == flowchartContext;
}

private static ValueTask ExecuteBasedOnMode(ActivityExecutionContext context, Func<ValueTask> tokenBasedAction, Func<ValueTask> counterBasedAction)
{
var mode = GetEffectiveExecutionMode(context);
Expand Down