Skip to content

feat(durable): read and stop executions with the application credential - #357

Merged
swkeever merged 4 commits into
mainfrom
skeever/durable-execution-data-plane
Oct 30, 2026
Merged

swkeever merged 4 commits into
mainfrom
skeever/durable-execution-data-plane

Conversation

@swkeever

@swkeever swkeever commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Tracking

Tracks: volcano-hosting#2364, the server support for reading and stopping an execution with the start's credentials. Coordination branch: skeever/durable-execution-data-plane, the same name in Hosting, Python, and Ruby.

volcano-hosting#2364 merged as 29807384cf, so the server support ships before this SDK release.

Summary

  • New methods. Both answer the { data, status, error } envelope with a DurableExecution, as get and stop do:
    • volcano.durable.getFromApplication(functionName, executionId, { clientToken? }) calls GET /durable-functions/{functionId}/executions/{executionId}.
    • volcano.durable.stopFromApplication(functionName, executionId, { clientToken? }) calls POST /durable-functions/{functionId}/executions/{executionId}/stop.
  • Credential. Both send the credential start sends: the user's session when there is one, otherwise the client's key. clientToken goes out as X-Volcano-Client-Token with every credential, a service key included, and no header is sent without one. A service key holding * reaches any execution; one scoped to a list without * needs the client token, as an anon key does. The SDK checks the function name, the execution id, and the token locally, with the rules durable.messages already applies, and refuses a bad value with status: null.
  • start and the new methods choose their credential in one shared helper. Owner-scoped get, list, and stop are unchanged.
  • OpenAPI. openapi/openapi.yaml is main's snapshot with Hosting's durable sections taken from its public bundle at main 1ccff82a16, after volcano-hosting#2364 merged (built with scripts/ci/openapi-bundle.sh, byte-identical to that commit's docs/public/api-reference/openapi.yaml). Every /durable-functions, /durable-callbacks, and project durable-function path, every Durable* component, and the service key scope note on client tokens match that bundle exactly; nothing else changes. The full bundle would also rename Autofix to LavaFlow and drop those keys from the exported OpenAPIOperations and OpenAPIComponents types, which an additive release must not carry; chore/sync-openapi (chore(api): sync OpenAPI contract #352) owns the full sync. The two operations are added to the orval allowlist, and the client is regenerated with pnpm generate:openapi.
  • Docs.
    • docs/durable-functions.md gains "Reading and stopping from the application".
    • docs/error-handling.md, the Durable doc comments, and the order pipeline example no longer say that reading or stopping needs the owner's token.
    • They say what shipped: only a service key holding * reaches every execution, including a pending one; a scoped key needs clientToken; and a throttled read or stop answers 503 with error.retryAfter, after which a stop may already have been sent.
    • docs/typescript.md lists both methods among those that resolve with DurableExecution.
  • Fixtures and types. The published-API fixture adds both methods. test/types/openapi-contract-durable.ts pins both routes, so a sync from a Hosting main without them fails.
  • Additive only. Release Please should cut a minor release.

Verification

On 3001ca0, under Node 26.0.0 (Node 22.23.3 from .node-version is not installed on this machine; CI runs it):

  • pnpm check:openapi: the regenerated client matches the commit.
  • pnpm lint and pnpm check:unused
  • pnpm test: 219 suites, 3,399 tests. The new __tests__/durable-executions-application.test.ts covers:
    • the path, method, and credential;
    • X-Volcano-Client-Token when a token is given, with an anon key, a session, or a service key, and no header when none is;
    • response mapping, 404 handling, and a 503 with Retry-After surfacing error.retryAfter, against transport doubles and over a mocked fetch.
  • pnpm test:types, including the published-API fixture (public-api-compatibility.d.ts), plus pnpm test:typed-runtime
  • pnpm quality:policy and pnpm run audit
  • pnpm test:package and pnpm test:quickstart
  • MUTATION_BASE=origin/main pnpm mutation:full: not rerun to completion locally. The runtime files are unchanged since 9d27d64, where Stryker killed all 248 mutants (durable-facade.ts 193, volcano-auth-config.ts 45, volcano-auth-facades.ts 10). CI's 32 mutation shards passed on d760f30.
  • pnpm test:tooling: 116 of 117 pass. "native reporter preserves cancelled case" times out under Node 26. That fixture's never-settling test, and the tooling, are unchanged here, so the Node 22 CI job decides it.

Left to CI: pnpm test:examples, which this change does not touch.

Cross-language impact

Classify this change: public facade / wire contract

  • Requirement IDs and affected behavior: none yet. volcano-hosting#2364 adds no tests/sdk-contract requirement or scenario for these reads and stops. A follow-up should add one, for example a client token reaching its execution and an anon key without one getting 404.
  • Companion PRs: Python (get_from_application / stop_from_application) and Ruby are in progress on the same branch name, skeever/durable-execution-data-plane.
  • Canonical scenarios, bindings, and active/staged copies: none. See above.
  • Public examples:
    • Here: docs/durable-functions.md and docs/error-handling.md.
    • Hosting: docs/public/functions/durable-functions.md in #2364.
    • Python and Ruby: in their PRs.
  • Native checks and shared acceptance evidence:
    • Native checks: above, on 3001ca0.
    • Shared acceptance: none. There is no scenario to run until one is added.

Coordination

Companion PRs, all on skeever/durable-execution-data-plane: #357, Kong/volcano-sdk-python#422, Kong/volcano-sdk-ruby#366.

Merge order:

  1. The server support, Kong/volcano-hosting#2364.
  2. These three SDK PRs, now that #2364 has merged.
  3. A hosting PR that adds the shared tests/sdk-contract scenarios for both routes.

🤖 Generated with Claude Code

Add durable.getFromApplication(functionName, executionId, { clientToken })
and durable.stopFromApplication(...), which call GET and POST stop on
/durable-functions/{functionId}/executions/{executionId} with the
credential durable.start uses: the user's session when there is one,
otherwise the client's key. An anon key, or a user who did not start the
execution, sends the start's client_token as X-Volcano-Client-Token.
Both answer the DurableExecution envelope that get and stop do.

Sync openapi/openapi.yaml from the public bundle of
Kong/volcano-hosting#2364 (6377c22be0), which adds the two routes, add
them to the orval allowlist, and regenerate. Docs, doc comments, and the
order pipeline example no longer say that reading or stopping an
execution needs the owner's token.
Vendor hosting main's public bundle (1ccff82a16), which Kong/volcano-hosting#2364
shipped, and regenerate the client.

A service key now reaches every execution only when it holds `*`. A key
scoped without `*` needs the execution's client token, as an anon key does,
and only a `*` key reaches a pending execution. Read and stop also answer 503
with Retry-After when reads of the execution's state are throttled; a stop
answered that way may already have been sent.

Update the Durable doc comments, the durable and error-handling guides, and
the order pipeline example to say so, and pin that a service key sends the
client token and that a throttled 503 surfaces `error.retryAfter`.
@swkeever
swkeever marked this pull request as ready for review October 29, 2026 21:05
@swkeever
swkeever requested a review from a team as a code owner October 29, 2026 21:05
Copilot AI balanced review requested due to automatic review settings October 29, 2026 21:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

AI review: no P0-P2 findings

Reviewed 3001ca0. Run log

Adds durable.getFromApplication and durable.stopFromApplication, which read and stop an execution with the client's own credential and an optional X-Volcano-Client-Token. The OpenAPI file now takes only Hosting main's durable sections, and the PR regenerates the client and updates the docs and tests. Both earlier findings are fixed: the Autofix keys are back in the exported OpenAPI types, and the TypeScript guide lists the new methods. The change is additive and low risk; the only finding left is minor (P3).

⚪ P3

  • src/sdk-public-types-durable.ts:90 The docs say to read error.retryAfter, but the durable envelope types error as plain Error

Not checked: The AI review read the diff, the code, and the PR's text; it ran no tests or builds and read nothing outside this repository.

  • Whether deployed Hosting serves both new application routes with the documented credential, client-token, 409 and 503 Retry-After behavior before this SDK ships.
  • Whether the copied durable sections of openapi/openapi.yaml match Hosting main 1ccff82a16 exactly.
  • Whether Hosting's CORS preflight allows X-Volcano-Client-Token on the new routes, so browser calls with an anon key succeed.
  • Verify deployed Hosting supports both application routes and enforces the documented credential, client-token, and throttling behavior.

Human review: not needed

@github-actions
github-actions Bot requested a review from subnetmarco October 29, 2026 21:10
Comment thread openapi/openapi.yaml Resolved
Comment thread src/generated/openapi.d.ts Resolved
The full bundle sync renamed Autofix to LavaFlow and removed those keys from
the exported OpenAPIOperations and OpenAPIComponents types, a break this
additive release must not carry. The chore/sync-openapi PR owns the full sync.

Start from main's snapshot and take from hosting main 1ccff82a16 every
/durable-functions, /durable-callbacks, and project durable path, every
Durable* component, and the service key scope note on client tokens, so those
sections match hosting main exactly. Regenerate the client.

List getFromApplication and stopFromApplication among the methods that
resolve with DurableExecution in the TypeScript guide.
Comment thread src/sdk-public-types-durable.ts Resolved
@swkeever
swkeever added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit a174c88 Oct 30, 2026
55 checks passed
@swkeever
swkeever deleted the skeever/durable-execution-data-plane branch October 30, 2026 14:17
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