Skip to content

Add InvokeAsync for chained durable function calls (DOTNET-8661)#2374

Draft
GarrettBeatty wants to merge 1 commit into
gcbeatty/durable-wave0from
gcbeatty/durable-invoke
Draft

Add InvokeAsync for chained durable function calls (DOTNET-8661)#2374
GarrettBeatty wants to merge 1 commit into
gcbeatty/durable-wave0from
gcbeatty/durable-invoke

Conversation

@GarrettBeatty
Copy link
Copy Markdown
Contributor

Summary

Adds chained-function invocation to the .NET Durable Execution SDK. InvokeAsync calls another durable function as a separate execution; the caller suspends until the chained function completes, with the result checkpointed for replay.

Stacked on top of #2372 (Wave 0 cross-cutting types).

Fixes DOTNET-8661.

Public surface

  • IDurableContext.InvokeAsync<TPayload, TResult> (reflection + AOT-safe overloads with positional ICheckpointSerializer<TPayload> and ICheckpointSerializer<TResult>)
  • InvokeConfig with Timeout (currently [Obsolete] — reserved for a future ChainedInvokeOptions wire field) and TenantId for tenant propagation
  • Exception subclass tree: InvokeException base + InvokeFailedException, InvokeTimedOutException, InvokeStoppedException

Internal

  • InvokeOperation<TPayload, TResult> mirrors WaitOperation's sync-flush START + SuspendAndAwait pattern. Replay maps STARTED/PENDING to re-suspend; SUCCEEDED to cached deserialize; FAILED/TIMED_OUT/STOPPED to typed exception subclasses.
  • ExecutionState.IsTerminalStatus now includes TimedOut (was missing).
  • LambdaDurableServiceClient.MapFromSdkOperation now preserves ErrorData and StackTrace fields across all operation types (Step, ChildContext, ChainedInvoke). Pre-existing data-loss bug fix.
  • Reuses TerminationReason.InvokePending and OperationSubTypes.Invoke from Wave 0.

Test plan

  • Build clean (zero warnings, TreatWarningsAsErrors enforced) on net8.0 and net10.0
  • 38 new unit tests pass alongside existing 165
  • 4 new integration tests build successfully (require AWS credentials to run): InvokeHappyPath, InvokeFailure, InvokeWithTenantId, InvokeReplayDeterminism. Extends DurableFunctionDeployment to support a downstream callee function with cross-Lambda IAM.

🤖 Generated with Claude Code


COPY bin/publish/ ${LAMBDA_TASK_ROOT}

ENTRYPOINT ["/var/task/bootstrap"]

COPY bin/publish/ ${LAMBDA_TASK_ROOT}

ENTRYPOINT ["/var/task/bootstrap"]

COPY bin/publish/ ${LAMBDA_TASK_ROOT}

ENTRYPOINT ["/var/task/bootstrap"]

COPY bin/publish/ ${LAMBDA_TASK_ROOT}

ENTRYPOINT ["/var/task/bootstrap"]

COPY bin/publish/ ${LAMBDA_TASK_ROOT}

ENTRYPOINT ["/var/task/bootstrap"]

COPY bin/publish/ ${LAMBDA_TASK_ROOT}

ENTRYPOINT ["/var/task/bootstrap"]

COPY bin/publish/ ${LAMBDA_TASK_ROOT}

ENTRYPOINT ["/var/task/bootstrap"]

COPY bin/publish/ ${LAMBDA_TASK_ROOT}

ENTRYPOINT ["/var/task/bootstrap"]
@GarrettBeatty GarrettBeatty force-pushed the gcbeatty/durable-invoke branch from 2e91110 to a7868f3 Compare May 14, 2026 21:49
@GarrettBeatty GarrettBeatty force-pushed the gcbeatty/durable-wave0 branch from 464c591 to d308c3b Compare May 14, 2026 21:49
Adds chained-function invocation to the .NET Durable Execution SDK.
InvokeAsync calls another durable function as a separate execution; the
caller suspends until the chained function completes, with the result
checkpointed for replay.

Public surface:
- IDurableContext.InvokeAsync<TPayload, TResult> (reflection + AOT-safe
  overloads with positional ICheckpointSerializer<TPayload> and
  ICheckpointSerializer<TResult>)
- InvokeConfig with Timeout (currently [Obsolete] - reserved for a future
  ChainedInvokeOptions wire field) and TenantId for tenant propagation
- Exception subclass tree: InvokeException base +
  InvokeFailedException, InvokeTimedOutException, InvokeStoppedException

Internal:
- InvokeOperation<TPayload, TResult> mirrors WaitOperation's sync-flush
  START + SuspendAndAwait pattern. Replay maps STARTED/PENDING to
  re-suspend; SUCCEEDED to cached deserialize; FAILED/TIMED_OUT/STOPPED
  to typed exception subclasses.
- ExecutionState.IsTerminalStatus now includes TimedOut (was missing).
- LambdaDurableServiceClient.MapFromSdkOperation now preserves ErrorData
  and StackTrace fields across all operation types (Step, ChildContext,
  ChainedInvoke). Pre-existing data-loss bug fix.
- Reuses TerminationReason.InvokePending and OperationSubTypes.Invoke
  from Wave 0.

Adds 38 unit tests + 4 integration tests covering happy path, failure
propagation, tenant-ID propagation, and replay determinism. Extends
DurableFunctionDeployment to support a downstream callee function with
cross-Lambda IAM.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@GarrettBeatty GarrettBeatty force-pushed the gcbeatty/durable-invoke branch from a7868f3 to 797d920 Compare May 14, 2026 22:19
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.

2 participants