Skip to content

Comments

Enable recursive termination of sub-orchestrations in gRPC sidecar#561

Closed
Copilot wants to merge 3 commits intomainfrom
copilot/terminate-sub-orchestrations
Closed

Enable recursive termination of sub-orchestrations in gRPC sidecar#561
Copilot wants to merge 3 commits intomainfrom
copilot/terminate-sub-orchestrations

Conversation

Copy link
Contributor

Copilot AI commented Dec 13, 2025

Terminating an orchestration needed to stop its sub-orchestrations recursively in isolated/sidecar scenarios without relying on client-side history crawling.

  • Behavior

    • gRPC sidecar now tracks sub-orchestration instance IDs from orchestrator actions and terminates them when a recursive terminate is requested.
    • Client termination path remains unchanged API-wise and delegates recursion to the sidecar.
  • Implementation

    • Added child-instance tracking in TaskHubGrpcServer and recursive terminate dispatch.
    • Removed client-side history-based recursion attempts.
    • Integration test ensures parent termination (recursive) terminates children.
  • Example

    await client.TerminateInstanceAsync(
        parentId,
        new TerminateInstanceOptions(Recursive: true),
        cancellationToken);
    // Sidecar will terminate tracked child orchestrations as well.
Original prompt

This section details on the original issue you should resolve

<issue_title>How to terminate sub-orchestrations ?</issue_title>
<issue_description>How can we terminate sub-orchestrations in isolated process ? By reading issue #4, I understand there is no plan to return an instance history. What would be the replacement for the following code ?

[FunctionName(nameof(Orchestration_StopInstance))]
public static async Task<IActionResult> Orchestration_StopInstance(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "orchestration/stop/{instanceId}")] HttpRequestMessage req,
    [DurableClient] IDurableOrchestrationClient orchestrationClient,
    string instanceId
)
{
    try
    {
        var durableOrchestrationStatus = await orchestrationClient.GetStatusAsync(instanceId, true, false, false);

        foreach (var subInstanceId in durableOrchestrationStatus.History.Select(t => t["InstanceId"]).Where(t => t != null))
        {
            await Orchestration_StopInstance(req, orchestrationClient, subInstanceId.ToString());
        }

        await orchestrationClient.TerminateAsync(instanceId, "Stopped");

        return new NoContentResult();
    }
    catch (Exception ex)
    {
        return new JsonResult(new Response(ex.Message.Trim())) { StatusCode = (int)HttpStatusCode.InternalServerError };
    }
}
```</issue_description>

<agent_instructions>see whats best way to support this in a non breaking way, and make the change</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@jviau</author><body>
Hi @gsimardimt - while not ideal, you can make and HTTP call to your own functions endpoint to get the orchestration history, and find sub-orchestration IDs that way: https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-http-api

In the future, we aim to solve your specific scenario by supporting orchestration cancellation (#7). No ETA on that though.</body></comment_new>
<comment_new><author>@jviau</author><body>
As mentioned in microsoft/durabletask-dotnet#4, we are hesitant to add this to public API surface. Instance history is more of an implementation detail, meant to be hidden from regular consumption. Individual backends are not really even supposed to be too aware of it. It is not something we are in a rush to expose and support as public API.</body></comment_new>
</comments>


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits December 13, 2025 23:15
Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
Co-authored-by: YunchuWang <12449837+YunchuWang@users.noreply.github.com>
Comment on lines +597 to +604
foreach (P.OrchestratorAction action in request.Actions)
{
if (action.OrchestratorActionTypeCase == P.OrchestratorAction.OrchestratorActionTypeOneofCase.CreateSubOrchestration &&
!string.IsNullOrEmpty(action.CreateSubOrchestration.InstanceId))
{
children.Add(action.CreateSubOrchestration.InstanceId);
}
}
Comment on lines +767 to +773
foreach (P.HistoryEvent e in protoNewEvents)
{
if (e.SubOrchestrationInstanceCreated?.InstanceId is string subId && !string.IsNullOrEmpty(subId))
{
children.Add(subId);
}
}
Copilot AI changed the title [WIP] Fix termination of sub-orchestrations in isolated process Enable recursive termination of sub-orchestrations in gRPC sidecar Dec 13, 2025
Copilot AI requested a review from YunchuWang December 13, 2025 23:25
@YunchuWang YunchuWang closed this Dec 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

How to terminate sub-orchestrations ?

2 participants