You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When the SDK suspends with no pending operation, it returns an output that the service rejects. The SDK should report this state as an SDK error. The error should name the operations that the suspended threads were waiting for.
The invocation should stay retryable. The race in #370 reached this state, and the execution still succeeded on a later invocation.
Actual Behavior
ExecutionManager calls preSuspendCheck() before it suspends. It does so in deregisterActiveThread and in finishCheckpointProcessing.
preSuspendCheck() looks for a pending operation: a STEP in PENDING, a WAIT or CALLBACK in STARTED, or a CHAINED_INVOKE in PENDING or STARTED.
If it finds none, it logs one WARN line: Invalid suspension. No operation is pending. The line does not name an operation or a thread.
The SDK then suspends and returns Status: PENDING with no error. The Lambda invocation succeeds, because the handler returns normally.
The service rejects the output with InvalidParameterValueException: Cannot return PENDING status with no pending operations.
If the cause is deterministic, every replay reaches the same state. The execution fails, and GetDurableExecution reports Status: FAILED with that error.
The customer sees Lambda invocations that succeed, one WARN line per invocation, and a failed execution. None of these names the operation or the SDK defect that caused the failure.
Keep the retry. A transient race can clear on a later invocation, as in [Bug]: failed tests due to unexpected PENDING status #370. DurableExecutor already rethrows a retryable UnrecoverableDurableExecutionException. Its comment says this is to "let the backend retry the invocation". An error on that path could keep the retry and name the cause.
Report it in local tests.LocalDurableTestRunner returns PENDING for this output. It could report the output as invalid, so that a local test shows the outcome the service produces.
A smaller change keeps the current behavior and logs at ERROR with the ID and name of the awaited operation.
Expected Behavior
When the SDK suspends with no pending operation, it returns an output that the service rejects. The SDK should report this state as an SDK error. The error should name the operations that the suspended threads were waiting for.
The invocation should stay retryable. The race in #370 reached this state, and the execution still succeeded on a later invocation.
Actual Behavior
ExecutionManagercallspreSuspendCheck()before it suspends. It does so inderegisterActiveThreadand infinishCheckpointProcessing.preSuspendCheck()looks for a pending operation: aSTEPinPENDING, aWAITorCALLBACKinSTARTED, or aCHAINED_INVOKEinPENDINGorSTARTED.Invalid suspension. No operation is pending. The line does not name an operation or a thread.Status: PENDINGwith no error. The Lambda invocation succeeds, because the handler returns normally.InvalidParameterValueException: Cannot return PENDING status with no pending operations.GetDurableExecutionreportsStatus: FAILEDwith that error.The customer sees Lambda invocations that succeed, one WARN line per invocation, and a failed execution. None of these names the operation or the SDK defect that caused the failure.
Steps to Reproduce
Run case 1 from [Bug]: get() on a SKIPPED parallel branch never returns, and the execution fails #752 with
LocalDurableTestRunner. That handler runs afirstSuccessful()parallel withmaxConcurrency(1), then callsget()on the skipped second branch.Each invocation returns status
PENDINGwith no error. No operation is pending.Each invocation logs:
LocalDurableTestRunner.runUntilCompletereturnsPENDING. It does not report that the service would reject the output.SDK Version
2.2.1. Reproduced on
mainat ef88276 (2.2.2-SNAPSHOT).Java Version
21
Is this a regression?
Unknown
Additional Context
Three SDK defects have reached this state. Each ended with the service error above.
allCompleted()branch registration. Fixed in Fix allCompleted parallel branch registration race #737.get()on aSKIPPEDparallel branch. Open.A fix needs to handle three things.
DurableExecutoralready rethrows a retryableUnrecoverableDurableExecutionException. Its comment says this is to "let the backend retry the invocation". An error on that path could keep the retry and name the cause.PENDINGreturn when a checkpoint response has no token. That path abandons in-flight operations, so the state can hold no pending operation. A stricter check must not reject that return.LocalDurableTestRunnerreturnsPENDINGfor this output. It could report the output as invalid, so that a local test shows the outcome the service produces.A smaller change keeps the current behavior and logs at ERROR with the ID and name of the awaited operation.