Repository navigation
feat(sdk): add subType to step and createCallback - #939
Merged
Merged
Conversation
ParidelPooya
had a problem deploying
to
ai-pr-review-runtime
October 1, 2026 03:21 — with
GitHub Actions
Failure
StepConfig.subType and CreateCallbackConfig.subType set the subtype of a step or a callback. They have the same shape as ChildConfig.subType. The SDK records the subtype on the checkpoint and passes it to plugin events. Replay compares it with the checkpoint. An unset or empty subtype selects the default, Step or Callback. The retry check compared the subtype with "Step". A step with a custom subtype does not match. So the check now compares the operation type with STEP, and such a step that waits for a retry still suspends with RETRY_SCHEDULED. The testing SDK's local checkpoint server now validates SubType as the service does: 1 to 32 characters from [a-zA-Z0-9-_]. An invalid subtype rejects the whole request with HTTP 400 ValidationException and the service's message. The worker thread used to drop the name and $metadata of its errors. It now sends them as plain objects, so the SDK classifies local checkpoint errors as it classifies the service's errors.
ParidelPooya
force-pushed
the
feat/sdk-step-callback-subtype
branch
from
October 1, 2026 04:10
9847fa3 to
fb42320
Compare
yaythomas
approved these changes
Oct 1, 2026
yaythomas
left a comment
Contributor
There was a problem hiding this comment.
this is strictly speaking "for every update" not just "for STEP and CONTEXT updates"
could you pls create tracking issues to implement in the sibling SDKs, referencing this one?
This was referenced Oct 1, 2026
ParidelPooya
added a commit
that referenced
this pull request
Oct 2, 2026
#939 is merged, and both packages sit at versions that npm already serves: the core SDK at 2.5.0 and the testing SDK at 1.2.0. Both are also already tagged (`sdk-2.5.0/test-1.2.0`). So neither package can be released until its version moves. This bumps: - `@aws/durable-execution-sdk-js` from 2.5.0 to 2.6.0. - `@aws/durable-execution-sdk-js-testing` from 1.2.0 to 1.3.0. Both bumps are minor. 1. The core SDK adds `StepConfig.subType` and `CreateCallbackConfig.subType` (#939). Both are new optional public API. No published API was removed or renamed. Without the option, the SDK records the same subtypes as before. 2. The testing SDK's local checkpoint server now validates `SubType` as the service does, and rejects an invalid one with HTTP 400 `ValidationException` (#939). A test that sent an invalid subtype passed before and fails now, as the same handler fails in AWS. This is new behavior, not a removed API, so it is a minor bump. The testing SDK's peer range on the core moves from `>=1.0.1 <=2.5.0` to `>=1.0.1 <=2.6.0`. That change is required: `src/__tests__/peer-compatibility.test.ts` asserts that the core SDK's current version satisfies the declared range. Every earlier core bump raised this bound the same way. No other package needs a change. The OTel plugin declares `>=2.4.0` and the Insight plugin `>=2.1.0`, and 2.6.0 satisfies both. The next PR adds `@aws/durable-execution-sdk-js-helpers`, which requires core `>=2.6.0`. It cannot install against the 2.5.0 in `main`, so it waits for this one. ### Testing - `npm ci` succeeds with the updated lockfile. The lockfile changes only the three version lines, as in #933. - Core SDK: `npm run build` and `npm test` pass (1281 tests). - Testing SDK: `npm run build` and `npm test` pass (1204 passed, 3 skipped), including `peer-compatibility.test.ts`.
ParidelPooya
added a commit
that referenced
this pull request
Oct 3, 2026
…package (#949) This PR adds two packages. Both are at `0.1.0-alpha.0`, and every export is marked `@experimental`. #### `@aws/durable-execution-sdk-js-extras` A durable function sometimes needs to run work that is too long or too heavy for one Lambda invocation, such as a CI build. A [Lambda MicroVM](https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html) can run that work. This package adds two operations that drive a MicroVM from a durable function: - `microvm(context, name, input, config)` launches a new MicroVM, delivers one job, waits for the result, and terminates the MicroVM. - `microvmSession(context, name, config, handler)` launches one MicroVM and lets the handler send it several jobs with `vm.invoke(ctx, name, input, options)`. The jobs share the MicroVM's files and processes. The session terminates the MicroVM when the handler returns or throws. The function invocation ends while the MicroVM works. So no Lambda compute is billed during the wait. 1. Both operations, and `vm.invoke`, are plain functions that take the context first. They are built only from `runInChildContext`, `step`, and `createCallback`. So they replay deterministically in the root context, in a child context, and in `map` and `parallel` items. 2. Each part records its own subtype, such as `MicrovmLaunch`, `MicrovmRequest`, and `MicrovmCallback`. The package exports them as `MicrovmOperationSubType`. 3. Those subtypes need the `subType` option of `step` and `createCallback`, which #939 added in core SDK 2.6.0. An older SDK ignores the option and records `Step` and `Callback`. A later upgrade would then change the recorded subtypes, and replay would fail executions in flight. 4. So the package's peer range on the core SDK is `>=2.6.0`. Other behavior, documented in the package README: - A job reaches the MicroVM through the `run` lifecycle hook payload when it fits in 4,096 Unicode code points, and over HTTP to the MicroVM endpoint otherwise. The launch step records the delivery, so every replay follows it. A session always uses HTTP. - Delivery retries in two tiers. A short retry window runs inside one step attempt, and the step retry strategy runs after it. Every call in the first tier ends 10 seconds before the invocation times out. In a session, the wait for a resume counts toward that window. - A session can opt in to let the worker suspend the MicroVM when it is idle (`autoSuspendOnIdle: true`, `autoSuspendIdleTime`). The next `vm.invoke` resumes it. It is off by default, so a default session needs only the permissions of `microvm` with HTTP delivery. #### `@aws/durable-execution-sdk-js-microvm-worker` This package runs in the MicroVM image. It is the other side of the contract that the extras package sends. - It answers the `run`, `resume`, `suspend`, and `terminate` lifecycle hooks. It acts only on the first valid `run` hook. - It runs each job in the background. It ignores a second delivery of a job while the job runs, and after it ended. It remembers the callback IDs of the last 1,000 finished jobs. - It sends `SendDurableExecutionCallbackHeartbeat` while a job runs, and reports the outcome with `SendDurableExecutionCallbackSuccess` or `SendDurableExecutionCallbackFailure`. Completion reporting retries up to 5 times, and each attempt ends after 30 seconds. - In a session that asks for it, it suspends its own MicroVM after the idle time, and refuses jobs with 503 while it suspends. The two packages do not depend on each other. One runs in the function, and the other runs in the MicroVM. So the JSON contract is declared in both. A contract test checks that the two declarations match, and a composed test runs the request step against the real worker listener. #### Repository changes - The root `build` and `test` scripts include both packages. - `lintcommit.js` accepts the `extras` and `microvm-worker` scopes. - `iterate-publish-npm.sh` lists both packages. The `insight-mcp` packaging test requires every non-private `@aws/` package to be in that list. Their version `0.1.0-alpha.0` is a prerelease, so the next release publishes them under the `beta` dist-tag, as it did for the Insight packages. - The CHANGELOG gains an "Added" entry for both packages. - The core README links to the extras package from its "Operation Subtypes" section. - `package-lock.json` adds `@aws-sdk/client-lambda-microvms` 3.1144.0. That client needs newer shared `@aws-sdk` and `@smithy` packages. So 20 of them move forward by a minor or patch version. No package is removed.
This was referenced Oct 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SDK:
subTypeonstepandcreateCallbackChildConfig.subTypealready lets such a function label its child context.SteporCallback.StepConfig.subTypeandCreateCallbackConfig.subTypenow set the subtype of a step or a callback. They have the same shape asChildConfig.subType. The SDK records the subtype on the checkpoint and passes it to plugin events. Replay compares it with the checkpoint. So a replayed operation whose subtype changed terminates as non-deterministic. An unset or empty subtype selects the default,SteporCallback.The core README gains an "Operation Subtypes" section with an example.
Why the retry check changes too
RETRY_SCHEDULED.Step.WAIT_SCHEDULEDorCALLBACK_PENDING.So the check now compares the operation type with
STEP. Only steps reach the retry-waiting state. AwaitForConditionis a step with the subtypeWaitForCondition. So it now also suspends withRETRY_SCHEDULEDwhile it waits for its next check.Testing SDK: the local checkpoint server validates
SubTypelike the service[a-zA-Z0-9-_].ValidationException, at START and at SUCCEED, for STEP and CONTEXT updates.1 validation error detected: Value 'bad subtype!' at 'updates.1.member.subType' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9-_]+.CheckpointUnrecoverableExecutionError. So the execution fails.The local checkpoint server accepted any subtype. So a test with an invalid subtype passed locally and failed in AWS. Now the local server runs the same check first, and throws the same
ValidationExceptionwith the same message.A second change was needed for the SDK to see that error as AWS sends it:
postMessage.postMessageclones anErrorwith its message and stack only. It drops thenameof a subclass, and properties such as$metadata.nameand its HTTP status in$metadata.name,$fault, and$metadata.Existing errors from the local server, such as
InvalidParameterValueExceptionfor an invalid state transition, carry no HTTP status. So their classification does not change.Follow-up PR:
The SDK does not check the subtype, so the service rejects an invalid one only after the step has already run. With the default retry semantics, a step with subtype Order Charge ran its code once and then the execution failed. A check in the SDK when step() or createCallback() is called would prevent that.