feat: add custom extension operations API - #607
Conversation
03121c7 to
a73d2d0
Compare
This comment has been minimized.
This comment has been minimized.
# Conflicts: # sdk-integration-tests/src/test/java/software/amazon/lambda/durable/PluginIntegrationTest.java # sdk/src/main/java/software/amazon/lambda/durable/execution/DurableExecutor.java # sdk/src/main/java/software/amazon/lambda/durable/plugin/PluginInfoConverter.java # sdk/src/test/java/software/amazon/lambda/durable/plugin/PluginInfoConverterTest.java
This comment has been minimized.
This comment has been minimized.
| Throwable throwable) { | ||
| var cause = software.amazon.lambda.durable.util.ExceptionHelper.unwrapCompletableFuture(throwable); | ||
| if (cause instanceof SuspendExecutionException || cause instanceof UnrecoverableDurableExecutionException) { | ||
| return CompletableFuture.failedFuture(cause); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
This comment has been minimized.
This comment has been minimized.
| return extensionContext | ||
| .reserve(backoffName(name, attempt)) | ||
| .waitAsync(OperationSubType.WAIT.getValue(), delay) | ||
| .thenCompose(ignored -> executeRetryLoop(name, operation, config, attempt + 1)); |
There was a problem hiding this comment.
Codex AI review · Finding arf_v1_efufskzwapiifaigbhd53nhmx6
[P1] Preserve the durable context across the retry backoff. If the wait completes in-process while another operation keeps the invocation active, this continuation runs on the completion/polling thread. executeRetryLoop then reads thread-local durable and extension contexts that were detached when the child returned its incomplete stage, causing IllegalStateException instead of attempt 2. Pass the captured contexts through the loop or restore both around this continuation, and add an integration test with a retrying branch and an active sibling.
| return (error, state, attempt) -> { | ||
| var decision = retryStrategy.makeRetryDecision(error, attempt); | ||
| return decision.shouldRetry() | ||
| ? ExtensionStepResult.retry(state, decision.delay()) |
There was a problem hiding this comment.
Codex AI review · Finding arf_v1_wleseolejcs67e5dfazmlwepne
[P2] Preserve legacy zero-delay retry compatibility. RetryDecision.retry(null) normalizes to Duration.ZERO, and existing step handling also accepted an explicit zero as an immediate retry. Passing either value to ExtensionStepResult.retry now invokes duration validation that rejects delays below one second, so existing custom RetryStrategy implementations throw instead of retrying. Handle zero specially in this adapter and cover both null and explicit-zero decisions.
Codex AI reviewTwo retry regressions remain. Review was static only as requested; tests were not run. Reviewed commit |
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
Issue Link, if available
Closes #571
Description
ExtensionContextandExtensionOperationSPI for composing SDK-owned durable primitives with stable reservations, custom subtypes, stateful step replay, and configurable child contexts.Durable*Operationfacades and move backend engines into theprimitivepackage.DurableContext,ParallelDurableFuture, and compatibility config APIs.Demo/Screenshots
Not applicable. This change adds Java SDK APIs and internal architecture; no visual interface is changed.
Checklist
Testing
Unit Tests
Yes. Added and updated unit coverage for extension reservations, stateful steps, child-context replay, operation facades/config conversion, primitive implementations, deterministic IDs, plugin metadata, and compatibility APIs.
Full SDK result: 1,202 tests passed.
Integration Tests
Yes. Added integration coverage for extension operations, static operation facades, extension concurrency, plugins, replay, callbacks, retries, map, and parallel behavior.
Full integration result: 413 tests passed.
Examples
No new example was required. Existing examples remain source-compatible and passed their test suite: 120 tests passed, with 34 cloud-only tests skipped by default.
Verification command:
The OpenTelemetry module also passed 163 tests. Spotless and diff checks pass.