Skip to content

feat(durable): read and stop executions with application credentials - #366

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

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

Conversation

@swkeever

@swkeever swkeever commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Change

A Ruby application can read and stop the durable executions it started, with the credential start already uses: the active session, then a service key, then the anon key. Before this, get and stop called only the owner routes, which need a platform token.

client.durable.get_from_application(function_name, execution_id, client_token: nil)  # => Volcano::DurableExecution
client.durable.stop_from_application(function_name, execution_id, client_token: nil) # => Volcano::DurableExecution
  • They call GET /durable-functions/{functionId}/executions/{executionId} and POST .../stop.
  • client_token: goes out as X-Volcano-Client-Token when given, with any credential, and is omitted otherwise. A service key holding * reaches any execution; one scoped to a list without * needs the token, as an anon key does. It is checked like the messages one: 1 to 128 printable ASCII characters.
  • 404 raises Volcano::Error::NotFoundError, which is also what a credential that cannot reach the execution gets. A 409 on stop (only a service key holding * reaches a pending execution) raises Volcano::Error::ConflictError. A 503 raises Volcano::Error::ServerError; the docs say a throttled stop may already have been sent. retry_after stays nil on it: the shared transport reads Retry-After only on 429, as the Python SDK does.
  • The owner-scoped get, list and stop are unchanged. Doc comments, docs/functions.md and the README no longer say an application credential can only start.
  • Purely additive.

Server support shipped in Kong/volcano-hosting#2364 (merged as 29807384cf).

Coordination branch: skeever/durable-execution-data-plane.

Contract snapshot

openapi/openapi.yaml takes only the durable sections #2364 changed, copied verbatim from Hosting main's public bundle (scripts/ci/openapi-bundle.sh at 1ccff82a16, byte-identical to docs/public/api-reference/openapi.yaml): the start, read and stop paths under /durable-functions/{functionId}/executions, the DurableClientToken parameter, and the DurableExecution schema. Those sections now parse equal to Hosting main's. That brings in what changed after the draft this PR first vendored: scoped service keys, * for pending, 503 Retry-After, the start's execution_name_held 409, and description text. The rest of Hosting's drift is left to the automated sync PR (#5). The client was regenerated with bin/generate-openapi, bin/check-openapi passes, and the pinned snapshot digest in spec/volcano_generation_spec.rb is updated.

Verification

bundle exec rake quality on 583625d (Ruby 3.4.10, Java 21):

  • quality:audit: no vulnerabilities. quality:generated: generated boundary up to date.
  • quality:lint: 417 files, no offenses.
  • quality:types: RBS validate and both Steep targets, no errors.
  • quality:spec: 2,197 examples, 0 failures. Line coverage 100% (5,907/5,907) and branch coverage 100% (1,645/1,645).
  • quality:defects: all five injected defects detected. quality:package: gem built and smoke-tested in an isolated install.

New specs cover:

  • the request path, method, Authorization and X-Volcano-Client-Token, through the real generated client (spec/volcano/durable_application_http_spec.rb), including the token sent with a service key;
  • which credential is used: anon, service key, or session;
  • response mapping;
  • 404 and 409, with the bodies these routes return (error only, no code);
  • argument checks before transport;
  • consumer type fixtures.

Cross-language impact

Classification: public facade and SDK-facing wire contract.

Coordination

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

Merge order:

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

🤖 Generated with Claude Code

Takes the hunks Kong/volcano-hosting#2364 adds to Hosting's public bundle:
GET and POST stop on /durable-functions/{functionId}/executions/{executionId},
the start description, and the client_token description. Regenerates the
internal client with bin/generate-openapi.
Adds Durable#get_from_application and Durable#stop_from_application. They
call the application route with the credential #start uses, and send the
execution's client token as X-Volcano-Client-Token when one is given. The
owner-scoped #get, #list and #stop are unchanged; their docs no longer say
an application credential can only start.
Splice the start, read and stop paths, the DurableClientToken parameter
and the DurableExecution schema from Hosting main's public bundle
(1ccff82a16), which #2364 merged into. A service key scoped to a list
without `*` now needs the client token, only a key holding `*` reaches a
pending execution, a throttled 503 carries Retry-After, and the start's
409 names `execution_name_held`. Regenerated with bin/generate-openapi.
…tops

A service key reaches any execution only when it holds `*`; one scoped
without it passes client_token: like an anon key. Pin that the token goes
out with a service key, say a 503 stop may already have been sent, and
use the error bodies the routes return (no code; 409 says the execution
was never started).
@swkeever
swkeever marked this pull request as ready for review October 29, 2026 21:17
@swkeever
swkeever requested a review from a team as a code owner October 29, 2026 21:17
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

AI review: no P0-P2 findings

Reviewed 03c61b9. Run log

Adds Durable#get_from_application and #stop_from_application. They call the new application routes with the credential start uses and send X-Volcano-Client-Token when a token is given. The PR also vendors the matching OpenAPI sections, regenerates the client, and adds transport wiring, RBS signatures, specs, and docs. The change is purely additive and low-risk. The earlier P2 is fixed at this head: the README, docs/functions.md and the get_from_application comment now say a private function raises NotFoundError, and only an anon key on an authenticated function (or a missing functions.invoke) raises PermissionDeniedError.

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 the vendored durable sections of openapi/openapi.yaml match Kong/volcano-hosting's public bundle at 1ccff82a16, as the description says.
  • Whether the live server follows the documented access rules for scoped service keys, pending executions, private vs authenticated functions, and 503 throttled stops.
  • The shared tests/sdk-contract acceptance scenarios for these two routes don't exist yet; a later Kong/volcano-hosting PR is planned to add them.
  • Verify the vendored durable OpenAPI sections match Kong/volcano-hosting's public bundle at 1ccff82a16.
  • Verify both routes against Hosting through shared acceptance scenarios covering credential scopes, visibility, pending executions, and throttled stops.

Human review: not needed

…ication reads

A visibility refusal raises PermissionDeniedError rather than NotFoundError,
and a service key scoped without * also needs functions.invoke.
Comment thread docs/functions.md Resolved
Comment thread README.md Resolved
A private function answers every credential but a service key with 404,
so it raises NotFoundError. Only a missing functions.invoke or an anonymous
key on an authenticated function raises PermissionDeniedError.
@swkeever
swkeever added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit e3082cc Oct 30, 2026
15 checks passed
@swkeever
swkeever deleted the skeever/durable-execution-data-plane branch October 30, 2026 14:16
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.

1 participant