Skip to content

Add transactional success completion for mutations - #238

Open
ianmacartney wants to merge 5 commits into
mainfrom
ian/transactional-completion
Open

ianmacartney wants to merge 5 commits into
mainfrom
ian/transactional-completion

Conversation

@ianmacartney

@ianmacartney ianmacartney commented Sep 10, 2026 •

Copy link
Copy Markdown
Member

Add completeTransactionally: true to enqueueMutation and enqueueMutationBatch. Successful work, its selected onComplete callback, and completion bookkeeping commit together. For example, if the callback writes a result and then throws, both its writes and the work's writes roll back instead of leaving successful work with a failed callback.

The existing mutation wrapper calls the completion helper directly, eliminating the separately scheduled completion mutation without adding another wrapper UDF. Completion errors escape the wrapper and fail the scheduled mutation; existing recovery later records a terminal failure and dispatches the failure callback if selected. The job occupies its concurrency slot until recovery runs. Ordinary work errors retain the existing failure-completion path. Default completion, failure/cancellation callbacks, and action/query execution retain their current behavior.

Based on current main, including merged #237 (status-filtered completion), with transactional mode restricted to mutations at the client type boundary and component runtime boundary. Batch items remain independent transactions. New stored and scheduled fields are optional for existing queued jobs. Nested work and success callback calls use transaction limits derived from remaining capacity, reserving room for bookkeeping. The existing Convex ^1.43 peer requirement covers nested transaction limits. The headroom helper reserves the database and scheduler resources used by completion bookkeeping, while allowing newer Convex versions to add unrelated transaction metrics.

Validation: build, typecheck, lint, formatting, and all 268 tests pass with Vitest 5.1 after restacking onto main. The local Convex deployment smoke check (npm run test:e2e) also passes, with generated component API files unchanged. Tests cover successful commits and payload cleanup, absent/filtered callbacks, rollback after callback errors and after late bookkeeping errors, actual scheduled-wrapper failure followed by recovery and deduplication, work errors, default callback behavior, stale wrapper replay, remaining-budget calculations, mutation batch routing, client rollback on callback failure for single and batch enqueue, cancellation, and action/query rejection before batch writes. Success-path tests also verify that no separate completion or callback mutation is scheduled.

Test limitations: convex-test 0.0.67 supports nested transactionLimits; component wrapper tests enable transaction-limit tracking. It does not simulate production OCC. It omits the error text from failed scheduled-job records, so recovery tests supply that missing field after an actual scheduled wrapper fails and rolls back.

Transactional query success is a separate stacked change in #239.

@pkg-pr-new

pkg-pr-new Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@convex-dev/workpool@238

commit: 2e19056

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 15 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/client/index.ts Resolved
Comment thread src/client/index.test.ts Resolved

ianmacartney commented Sep 10, 2026 •

Copy link
Copy Markdown
Member Author

@ianmacartney
ianmacartney force-pushed the ian/transactional-completion branch from 14eabf7 to b304b6c Compare September 11, 2026 03:55
@ianmacartney
ianmacartney changed the base branch from ian/on-complete-statuses to graphite-base/238 September 11, 2026 20:34
@ianmacartney
ianmacartney force-pushed the ian/transactional-completion branch from b304b6c to 50482e2 Compare September 11, 2026 20:37
@ianmacartney
ianmacartney changed the base branch from graphite-base/238 to ian/on-complete-statuses September 11, 2026 20:37

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/client/index.ts Resolved
@ianmacartney
ianmacartney changed the base branch from ian/on-complete-statuses to graphite-base/238 September 11, 2026 23:28
ianmacartney added a commit that referenced this pull request Sep 11, 2026
Callers who only need failure or cancellation handling can now reuse one `onComplete` handler with `onCompleteExcludeKinds: ["success"]`. 

Mutation-only transactional success is a separate stacked change in #238, and for queries in #239.
@ianmacartney
ianmacartney force-pushed the ian/transactional-completion branch from 6d086a2 to de31804 Compare September 11, 2026 23:28
@cursor
cursor Bot changed the base branch from graphite-base/238 to main September 11, 2026 23:29
@ianmacartney
ianmacartney force-pushed the ian/transactional-completion branch 2 times, most recently from a8d4623 to 32e5f21 Compare September 11, 2026 23:36
worker.test.ts still inserted `statuses` into the component's onComplete
object, which fails validation at runtime and broke CI. Rename the
remaining `statuses`/`onCompleteStatuses` sites left over from the
exclusion rename, inverting each value to its complement.

Rename MutationEnqueueOptions to TransactionalEnqueueOptions so the name
describes the capability rather than the function type, leaving room for
queries to support it later.

Tie completeTransactionally to FnType in the standalone enqueue and
enqueueBatch helpers. They previously accepted the mutation options type
for every function type, so actions and queries type-checked and then
failed at runtime in the component.
The FnType gate on the standalone enqueue helpers used a naked type
parameter, so a union such as "mutation" | "action" distributed to
boolean | never and let completeTransactionally through. The call then
failed at runtime in the component instead of at the client boundary.

Check the parameter as a tuple so the union is tested as a whole, and
cover both helpers with a union FnType in the type test.
@ianmacartney
ianmacartney force-pushed the ian/transactional-completion branch from bec8e66 to 2e19056 Compare November 12, 2026 21:44
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