Skip to content

feat: standalone activities and cross-queue executeActivity - #471

Merged
btravers merged 3 commits into
mainfrom
feat/standalone-activities
Oct 14, 2026
Merged

btravers merged 3 commits into
mainfrom
feat/standalone-activities

Conversation

@btravers

@btravers btravers commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #467. Refs #452.

Client: standalone activities

const result = await client.for(pdfContract).executeActivity("renderInvoice", {
  activityId: `invoice-${id}`,
  args: { invoiceId: id },
});
  • ContractClient.startActivity / executeActivity / getActivityHandle run a contract's global activity with no workflow around it (Temporal Server 1.32+).
  • The task queue comes from the contract. args is validated before start; the result is parsed against the output schema.
  • TypedActivityHandle.result() rehydrates the activity's declared errors into ContractError, and maps cancelled / terminated / timed-out executions to ActivityCancelledError / ActivityTerminatedError / ActivityTimeoutError. Other failures are ActivityFailedError. describe / cancel / terminate return ActivityExecutionNotFoundError for an unknown ID.
  • New pattern groups: ACTIVITY_START_PATTERNS, ACTIVITY_RESULT_PATTERNS, ACTIVITY_EXECUTE_PATTERNS.
  • Contract activityOptions are the defaults; call options shallow-merge over them. The merged options must have a per-attempt and a total bound, or the call is a defect.

Worker: context.executeActivity (related to #452)

This is the alternative floated in the maintainer's comment on #452 (routing comes from the activity-only contract that hosts the activity). It does not implement #452's ask, taskQueue in ContractActivityOptions, and #452 is waiting on the reporter's feedback, so this PR doesn't close it.

context.executeActivity(pdfContract, "renderInvoice", { args: { invoiceId } })
  • Same shape as executeChildWorkflow: the queue comes from the target contract, so it's written once, on the contract whose worker polls it.
  • Same validation and error mapping as context.activities.X.
  • Options merge: workflow activityOptions < activity's contract activityOptions < per-call. taskQueue is not accepted.

Other changes

  • Activity bound predicates move to @temporal-contract/contract/internal, shared by client and worker.
  • Docs: new how-to run-activities-on-a-dedicated-queue, client/worker reference updates, routing pointer in tune-activity-options, middleware note that a standalone call has no workflowExecution.
  • EXAMPLES.md marks standalone activities ✅.

Testing

  • Unit: execute-activity.spec.ts (worker), typing tests in both packages' types-inference.spec.ts.
  • Integration: worker routing.spec.ts registers the activity only on the activity-only contract's worker, so the workflow completes only if routing works.
  • Client standalone-activity.spec.ts uses TestWorkflowEnvironment.createLocal() (CLI dev server, Temporal 1.32.0), because the testcontainers auto-setup image stops at 1.29. Adds @temporalio/testing as a client devDependency.

Not included

  • Workflow-scoped activities can't be targeted, only global ones.
  • client.activity.list / count aren't wrapped; use raw.
  • The testing package's default server image is unchanged.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Start, execute, and manage standalone contract activities directly from a client, with typed inputs, results, and errors.
    • Call activities on another contract’s dedicated task queue from a workflow using executeActivity. Activity options are combined across workflow, contract, and call settings; per-attempt and total time bounds are required.
  • Documentation
    • Added a guide to running activities on dedicated queues and expanded client, worker, and activity-routing references.
    • Documented that standalone client activity calls require Temporal Server 1.32 or later.

Client: ContractClient.startActivity / executeActivity / getActivityHandle
run a contract's global activity with no workflow (Temporal Server 1.32+),
on the contract's task queue, with input/output validation and declared
errors rehydrated into ContractError.

Worker: context.executeActivity(contract, name, { args, ...options })
calls another contract's activity from a workflow; the task queue comes
from the target contract, so it is written once, on the contract whose
worker polls it.

Activity bound predicates move to @temporal-contract/contract/internal so
client and worker share one copy.

Closes #467
Refs #452

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 14, 2026 10:22
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-14T12:31:57.826852Z 9d77358 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 40 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: btravstack/temporal-contract/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 677bc864-61b9-49cd-b47a-534b494e84a1
📥 Commits

Reviewing files that changed from the base of the PR and between 9be5cd0 and 9d77358.

📒 Files selected for processing: 3
  • docs/how-to/run-activities-on-a-dedicated-queue.md
  • packages/client/src/__tests__/standalone-activity.spec.ts
  • packages/client/src/activity.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: btravstack/temporal-contract/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3d2d99a4-bbb2-44d8-b753-319cd2c4e3da
📥 Commits

Reviewing files that changed from the base of the PR and between 18232af and 9be5cd0.

📒 Files selected for processing: 5
  • docs/how-to/run-activities-on-a-dedicated-queue.md
  • docs/reference/client-surface.md
  • packages/client/src/client.ts
  • packages/client/src/error-patterns.spec.ts
  • packages/worker/src/workflow.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

This change adds typed standalone activity operations to ContractClient and adds WorkflowContext.executeActivity for activities declared by another contract. Both paths use contract task queues and include activity validation, result typing, and bounded-option checks.

Changes: Contract activity execution

Layer / File(s) Summary
Shared activity bounds
packages/contract/src/activity-bounds.ts, packages/contract/src/internal.ts, packages/worker/src/activity-bounds.ts, packages/contract/src/types.ts
Adds shared checks for per-attempt and total activity bounds. The worker uses the shared checks, and the contract task-queue guidance describes routing through an activity-only contract.
Workflow activity execution
packages/worker/src/activities-proxy.ts, packages/worker/src/workflow.ts, packages/worker/src/__tests__/*, docs/how-to/*, docs/reference/worker-surface.md, docs/.vitepress/config.ts, .changeset/worker-execute-activity.md, EXAMPLES.md
Adds WorkflowContext.executeActivity for typed calls to activities on a target contract’s task queue. It merges workflow, contract, and call options, validates activity inputs, and reports undeclared activities or missing bounds as defects. Tests cover typing, validation, options, and routing. Documentation describes the API and dedicated-queue usage.
Standalone client activities
packages/client/src/activity.ts, packages/client/src/client.ts, packages/client/src/{options,types,errors,error-tags,error-patterns,internal,index}.ts, packages/client/src/__tests__/*, packages/testing/src/test-rig.spec.ts, docs/how-to/run-activities-on-a-dedicated-queue.md, docs/reference/client-surface.md, .changeset/client-standalone-activities.md, EXAMPLES.md
Adds ContractClient.startActivity, executeActivity, and getActivityHandle, with typed options, handles, results, and activity errors. Client tests cover results, declared failures, validation, duplicate IDs, handle operations, and missing bounds. Documentation states the Temporal Server version requirement and describes the APIs.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant WorkflowContext
  participant createExecuteActivity
  participant proxyActivities
  participant ActivityWorker
  WorkflowContext->>createExecuteActivity: call with target contract, activity name, and args
  createExecuteActivity->>proxyActivities: dispatch with merged options and target task queue
  proxyActivities->>ActivityWorker: run validated activity
  ActivityWorker-->>WorkflowContext: return activity result or failure
Loading
sequenceDiagram
  participant ContractClient
  participant TemporalServer
  participant ActivityWorker
  ContractClient->>TemporalServer: start activity on contract task queue
  TemporalServer->>ActivityWorker: dispatch activity execution
  ActivityWorker-->>TemporalServer: return activity result or failure
  TemporalServer-->>ContractClient: provide result to typed handle
Loading
Merge Risk: ⚪ Minimal · up to 9be5c

No actionable merge-blocking issue is established; the change is mergeable after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Out of Scope Changes check Warning Issue #467 concerns the typed client surface for standalone activities. The PR also adds WorkflowContext.executeActivity, its worker implementation, worker tests, worker routing changes, and worker … Remove the context.executeActivity implementation, its dedicated tests, routing changes, and dedicated documentation from this PR, or make #452 an active directly linked issue if that work is intended to remain.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Issue #467 requires typed client APIs for standalone global activities. The PR adds ContractClient.startActivity, executeActivity, and getActivityHandle. The reported implementation uses the con…
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 27 files. (2 skipped: …
Title check Passed The title "feat: standalone activities and cross-queue executeActivity" matches the main changes: client-side standalone activity support (startActivity, executeActivity, getActivityHandle) and the wo…
Description check Passed The description follows the template. It has a Summary section that explains the client and worker changes, the reasons for them, and linked issues (#467, #452). It also covers testing and exclusions.…
Full details: Out of Scope Changes check

Explanation

Issue #467 concerns the typed client surface for standalone activities. The PR also adds WorkflowContext.executeActivity, its worker implementation, worker tests, worker routing changes, and worker documentation. The linked issue states that worker registration already serves standalone activities. These changes implement a separate workflow-to-activity API and are not needed for the #467 client objective. The PR only references #452; that reference does not make #452 an active directly linked target for this assessment.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 18232af181

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/worker/src/workflow.ts
Comment thread packages/client/src/client.ts Outdated
Comment thread packages/worker/src/workflow.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

It introduces a large new public API surface spanning client, worker, and contract packages and depends on Temporal's newer standalone-activity API that cannot be fully verified here, warranting human review.

1 open finding
What changed in this PR

This PR adds typed standalone activity execution on two surfaces, closing #467 and answering #452. It lets a client run a contract's global activity directly (no workflow) via ContractClient.startActivity / executeActivity / getActivityHandle (Temporal Server ≥ 1.32), and lets a workflow run another contract's global activity on that contract's own task queue via context.executeActivity(contract, name, { args }). Both reuse the existing validate-on-send / parse-on-receive wrapper and contract-error rehydration, so routing a rate-limited/dedicated-pool activity no longer requires a duplicated activityOptionsByName taskQueue entry per calling workflow. The activity-bound predicates move to @temporal-contract/contract/internal so client and worker enforce the same per-attempt/total bound rules.

Changes:

  • Client: new activity.ts (typed handle + startActivity), seven new error classes/tags, three pattern groups, option/type additions, and ContractClient methods.
  • Worker: context.executeActivity built from a shared, bound-checked, option-merging wrapper on the target contract's queue.
  • Contract: extracted activity-bounds.ts (structural, Temporal-free) re-exported as _internal_*; docs, changesets, and E2E/typing tests.
File Description
packages/​contract/​src/​activity-bounds.ts New shared, structural bound predicates (per-attempt/total).
packages/​contract/​src/​internal.ts Re-exports bound predicates under _internal_ prefix.
packages/​worker/​src/​activity-bounds.ts Now re-exports the shared predicates; keeps BoundViolation/messages.
packages/​worker/​src/​activities-proxy.ts Adds createExecuteActivity, ContractActivityOf, TypedExecuteActivityOptions.
packages/​worker/​src/​workflow.ts Wires executeActivity into WorkflowContext with docs/types.
packages/​worker/​src/​middleware.ts Documents absent workflowExecution for standalone calls.
packages/​worker/​src/​{execute-activity,types-inference,tests/​routing*}.spec/​contract/​workflows Unit + E2E routing coverage for executeActivity.
packages/​client/​src/​activity.ts New typed activity handle, start/classify logic.
packages/​client/​src/​{errors,error-tags,error-patterns}.ts New activity error classes, tags, and pattern groups.
packages/​client/​src/​{types,options,internal,client,index,handle}.ts Types/options, lookupActivity, generalized rehydrateFailedResult, public API.
packages/​client/​src/​__tests__/​standalone-activity.spec.ts + types-inference.spec.ts E2E (CLI dev server) + typing coverage.
packages/​{client/​package.json, ...}, pnpm-lock.yaml Adds @temporalio/testing client devDependency.
packages/​testing/​src/​test-rig.spec.ts Marks new standalone methods as non-start.
docs/​**, EXAMPLES.md, .changeset/​* New how-to, reference updates, routing pointers, changesets.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/client/src/error-patterns.ts
- getActivityHandle takes runId in a trailing options bag, like getHandle
- re-export TypedExecuteActivityOptions from @temporal-contract/worker/workflow
- pin the ACTIVITY_* pattern groups in error-patterns.spec.ts

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9be5cd0f74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/client/src/activity.ts
Under idConflictPolicy "USE_EXISTING", Temporal returns whichever running
execution holds the activity ID. Describe it and report a type or queue
mismatch as ActivityAlreadyStartedError instead of typing an unrelated
execution with this activity's schemas.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d773587e9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/client/src/client.ts
@btravers
btravers merged commit 9fc7736 into main Oct 14, 2026
14 checks passed
@btravers
btravers deleted the feat/standalone-activities branch October 14, 2026 12:34
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.

client: typed standalone activity execution (client.activity.start / execute)

2 participants