GeezerVison is showing github.com — feat(sdk,core,webapp,run-engine): task concurrency option and shareable named limits by matt-aitken · Pull Request #4827 · triggerdotdev/trigger.dev
Conversation
matt-aitken
commented
Aug 29, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Summary
Stacked on #4826. Adds the concurrency option to task(): an inline shape caps the task itself, and concurrencyLimit() declares a named limit any task can hold (up to two named limits per task, shared across every holder). A trigger call can switch a run's named limits with its own concurrency option; the task's inline limit always applies.
import { concurrencyLimit, task } from "@trigger.dev/sdk";
export const openaiLimit = concurrencyLimit({ name: "openai", total: 25 });
export const generateSummary = task({
id: "generate-summary",
concurrency: [{ perKey: 1, total: 5 }, openaiLimit],
run: async (payload) => {},
});
await generateSummary.trigger(payload, { concurrency: ["openai"] });
perKey caps each concurrencyKey pool (runs without a key share one pool) and total caps every run holding the limit, keys or not. Queues stay pure ordering: the queue-level concurrencyLimit option keeps working unchanged and is deprecated in favor of concurrency. Limit names use a queue-safe charset (letters, numbers, underscores, hyphens; 1-122 characters), enforced by the factory, at deploy time and at trigger time, so distinct names can never merge after sanitization.
The runtime management surface (the concurrencyLimits namespace: list, retrieve, override, reset) rides this contract; its server side lands higher in the stack.
Design
The SDK normalizes concurrency into the task manifest (an inline shape plus named-limit references); the deploy compiler materializes named limits as dedicated queue rows and compiles inline limits into the task's own queue or an anonymous limit, so the trigger path keeps its current query count. Trigger-time names resolve server-side into the run's gate list, which is stored on the run (replays reuse it) and enforced by the engine mechanism from #4826. A run holds at most four gates end to end: three requested plus the task's anonymous inline-limit gate, so replays survive a task gaining an inline limit after the run was created.
Also renames the public queue option from totalConcurrencyLimit to combinedConcurrencyLimit (introduced lower in this stack, renamed here before anything ships). Engine internals and storage keep their existing names.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
🦋 Changeset detected
Latest commit: a0642e9
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 27 packages
| Name |
Type |
| @trigger.dev/core |
Patch |
| @trigger.dev/sdk |
Patch |
| @trigger.dev/react-hooks |
Patch |
| @trigger.dev/build |
Patch |
| trigger.dev |
Patch |
| @trigger.dev/python |
Patch |
| @trigger.dev/redis-worker |
Patch |
| @trigger.dev/schema-to-json |
Patch |
| @internal/clickhouse |
Patch |
| @internal/llm-model-catalog |
Patch |
| @internal/metrics-pipeline |
Patch |
| @trigger.dev/rbac |
Patch |
| @internal/redis |
Patch |
| @internal/replication |
Patch |
| @internal/run-engine |
Patch |
| @internal/run-store |
Patch |
| @internal/schedule-engine |
Patch |
| @internal/tracing |
Patch |
| @internal/webhook-engine |
Patch |
| @internal/webhook-sources |
Patch |
| @internal/dashboard-agent |
Patch |
| @internal/cache |
Patch |
| @trigger.dev/rsc |
Patch |
| @trigger.dev/database |
Patch |
| @trigger.dev/otlp-importer |
Patch |
| @trigger.dev/sso |
Patch |
| @internal/testcontainers |
Patch |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
coderabbitai
Bot
commented
Aug 29, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
|

Important
Review skipped
The saved review history does not include the base for the last reviewed commit. This saved history cannot establish the base for an incremental review. Comment @coderabbitai full review to establish a new review baseline. No full review was started, and the last reviewed checkpoint was preserved.
You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.
Use the checkbox below for a quick retry:
Note
Reviews paused
It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.
Use the following commands to manage reviews:
@coderabbitai resume to resume automatic reviews.
@coderabbitai review to trigger a single review.
Use the checkboxes below for quick actions:
- ▶️ Resume reviews
- 🔍 Trigger review
No actionable comments were generated in the recent review. 🎉
ℹ️ Recent review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Team
Run ID: ea8833e5-9f69-4027-b61d-9aed754dc5ff
📥 Commits
Reviewing files that changed from the base of the PR and between 894ac6e and 499479c.
📒 Files selected for processing (1)
packages/core/src/v3/schemas/build.ts
Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.
📜 Recent review details
⏰ Context from checks skipped due to timeout. (50)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (9, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (19, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (20, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (15, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (24, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (21, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (12, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (16, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (11, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (18, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (22, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (4, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (13, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (8, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (23, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (10, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (17, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (7, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (14, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (2, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (6, 24)
- GitHub Check: sdk-compat / Node.js 24.18 (warp-ubuntu-latest-x64-4x)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (1, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (3, 24)
- GitHub Check: webapp / 🧪 Unit Tests: Webapp (5, 24)
- GitHub Check: e2e / 🧪 CLI v3 tests (warp-ubuntu-latest-x64-4x - npm)
- GitHub Check: sdk-compat / Node.js 20.20 (warp-ubuntu-latest-x64-4x)
- GitHub Check: sdk-compat / Node.js 22.23 (warp-ubuntu-latest-x64-4x)
- GitHub Check: sdk-compat / Node.js 26.4 (warp-ubuntu-latest-x64-4x)
- GitHub Check: packages / 🧪 Unit Tests: Packages (1, 3)
- GitHub Check: e2e / 🧪 CLI v3 tests (warp-ubuntu-latest-x64-4x - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (warp-windows-latest-x64-8x - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (warp-windows-latest-x64-8x - npm)
- GitHub Check: sdk-compat / Cloudflare Workers
- GitHub Check: sdk-compat / Bun Runtime
- GitHub Check: sdk-compat / Deno Runtime
- GitHub Check: obsmap / 🧪 Unit Tests: Observability Map
- GitHub Check: packages / 🧪 Unit Tests: Packages (2, 3)
- GitHub Check: internal / 🧪 Unit Tests: Internal
- GitHub Check: runops-guard / runops-guard
- GitHub Check: e2e-webapp / 🧪 E2E Tests: Webapp (1, 2)
- GitHub Check: typecheck / typecheck
- GitHub Check: packages / 🧪 Unit Tests: Packages (3, 3)
- GitHub Check: e2e-webapp / 🧪 E2E Tests: Webapp (2, 2)
- GitHub Check: fk-cascade-guard / fk-cascade-guard
- GitHub Check: code-quality / code-quality
- GitHub Check: audit
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: audit
- GitHub Check: Build and publish previews
🧰 Additional context used
📓 Path-based instructions (8)
**Import subpaths only** (never root).
📄 CodeRabbit inference engine (AGENTS.md)
Files:
packages/core/src/v3/schemas/build.ts
**Prefer static imports over dynamic imports.**
📄 CodeRabbit inference engine (AGENTS.md)
Files:
packages/core/src/v3/schemas/build.ts
Add crumbs as you write code — not just when debugging.
📄 CodeRabbit inference engine (AGENTS.md)
Files:
packages/core/src/v3/schemas/build.ts
Use zod for validation in packages/core and apps/webapp
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
packages/core/src/v3/schemas/build.ts
Never import the root package (`@trigger.dev/core`).
📄 CodeRabbit inference engine (packages/core/CLAUDE.md)
Files:
packages/core/src/v3/schemas/build.ts
Use function declarations instead of default exports
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
packages/core/src/v3/schemas/build.ts
Use types over interfaces for TypeScript Avoid using enums; prefer string unions or const objects instead
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
packages/core/src/v3/schemas/build.ts
When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs Do not use high-cardinality attributes in OTEL metr...
📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)
Files:
packages/core/src/v3/schemas/build.ts
🔇 Additional comments (2)
packages/core/src/v3/schemas/build.ts (2)
10-10: LGTM!
119-119: LGTM!
Walkthrough
The change adds task-level inline and named concurrency limits with per-key and total caps. It replaces queue gate tuple configuration with explicit concurrency and trigger options. It persists and validates queue gates across task metadata, runs, queues, and replay flows. It adds concurrency metadata to worker manifests and resource catalogs. It also renames queue concurrency ceilings to combinedConcurrencyLimit and adds integration and parser tests.
Merge Risk: 🟡 Moderate · up to 49947
This change exposes queue gates and concurrency limits across task triggering and worker manifests, but unresolved SDK and metadata behaviors can cause requested concurrency controls to be ignored, truncated, or interpreted differently than configured. Resolve these issues before merge.
🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
| Check name |
Status |
Explanation |
Resolution |
| Docstring Coverage |
⚠️ Warning |
Docstring coverage is 39.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 28 functions across 31 files. |
Write docstrings for the functions missing them to satisfy the coverage threshold. |
| Description check |
⚠️ Warning |
The description gives a detailed and relevant summary of the concurrency changes, but it does not follow the repository template. It omits the issue-closing line, checklist, testing section, changelog… |
Add the required template sections. Include a valid Closes #<issue> reference, complete the checklist, describe the testing performed, add a short changelog entry, and state N/A for screenshots if none apply. |
✅ Passed checks (3 passed)
| Check name |
Status |
Explanation |
| Linked Issues check |
✅ Passed |
Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check |
✅ Passed |
Check skipped because no linked issues were found for this pull request. |
| Title check |
✅ Passed |
The title clearly summarizes the main change: adding task concurrency options and shareable named limits across the SDK, core, webapp, and run engine. |
Full details: Description check
Explanation
The description gives a detailed and relevant summary of the concurrency changes, but it does not follow the repository template. It omits the issue-closing line, checklist, testing section, changelog section, and screenshots section.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
feat/queue-gates-contract
Comment @coderabbitai help to get the list of available commands.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
pkg-pr-new
Bot
commented
Aug 29, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
|
Open in StackBlitz
@trigger.dev/build
npm i https://pkg.pr.new/@trigger.dev/build@a0642e9
trigger.dev
npm i https://pkg.pr.new/trigger.dev@a0642e9
@trigger.dev/core
npm i https://pkg.pr.new/@trigger.dev/core@a0642e9
@trigger.dev/python
npm i https://pkg.pr.new/@trigger.dev/python@a0642e9
@trigger.dev/react-hooks
npm i https://pkg.pr.new/@trigger.dev/react-hooks@a0642e9
@trigger.dev/redis-worker
npm i https://pkg.pr.new/@trigger.dev/redis-worker@a0642e9
@trigger.dev/rsc
npm i https://pkg.pr.new/@trigger.dev/rsc@a0642e9
@trigger.dev/schema-to-json
npm i https://pkg.pr.new/@trigger.dev/schema-to-json@a0642e9
@trigger.dev/sdk
npm i https://pkg.pr.new/@trigger.dev/sdk@a0642e9
commit: a0642e9
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
devin-ai-integration
Bot
left a comment
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note This report is out of date. Scroll down for Devin Review's latest report on this PR.
Devin Review found 0 new potential issues.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
devin-ai-integration
Bot
left a comment
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note This report is out of date. Scroll down for Devin Review's latest report on this PR.
Devin Review found 0 new potential issues.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Two definitions of the same queue that differ only in combinedConcurrencyLimit
now warn and keep the first definition instead of letting registration order
pick the deployed cap.
A bare string home (alone or as a tuple's first element) no longer registers
queue metadata, so module evaluation order can no longer shadow a declared
queue's limits with an empty definition.
Both gate parsers now drop gates with empty or over-length queue names,
drop gates whose literal key exceeds the manifest cap, and treat an
empty-string key as omitted so it inherits the run's key instead of
pinning an empty pool.
The webapp and the enqueue system carried identical copies of the gate
contract with nothing enforcing their parity. parseGates now lives in
the run-engine package with unit tests covering every rule (bounds kept
inclusive at 128, empty keys inherit, malformed entries dropped, capped
at two), and both callers delegate to it.
Tasks declare concurrency directly: an inline { perKey, total } shape
caps the task, and concurrencyLimit() declares a named, shareable limit
that tasks hold via the same option (at most one inline plus two named).
Trigger calls switch a run's named limits with their own concurrency
option, strings only like queue. The queue tuple syntax and
combinedConcurrencyLimit never ship: queue() is a line again, its
concurrencyLimit deprecated in place, and the manifest carries the new
declarations for the server to compile.
Removes the combined override client methods the previous commit
intended to drop, moves react-hooks trigger options off the queue tuple
onto the concurrency names, merges a duplicated type import, and marks
the new type-only imports as such for the linter.
Passing undefined for a gateless original fell back to the task's
current gates, so old runs replayed after new limits were added would
silently gain them.
The index workers emit them into WorkerManifest, which is a separate
schema from the deploy metadata and also needs the field.
The option was silently dropped by the seven single-task and
subscribe/wait paths and doubled at four by-id batch sites. A named
limit object written inline in a task's concurrency now registers as a
declaration instead of losing its caps, and trigger-time limit names
must be non-empty strings.
Names are 1-122 characters of letters, numbers, underscores and
hyphens, checked by the factory, task declarations and trigger
options alike, so distinct names always stay distinct after queue
name sanitization.
…d limits
The end-to-end gate capacity is three (the anonymous inline-limit gate
plus two named limits), so trigger-time replacement can no longer lose
a named limit to a downstream cap. Limit shapes also start at 1: block
everything is a pause or an override, not a declared limit, so a stored
zero always reads as no limit.
Gate capacity is four end to end (three requested gates plus the
task's anonymous inline-limit gate), so replaying a three-gate run
against a task that later gained an inline limit resolves to four and
still enqueues. A run stored without gates now replays with the task's
currently declared limits instead of a fabricated empty array that
silently cleared them, matching how replays adopt the current queue
and retry config.
devin-ai-integration
Bot
left a comment
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note This report is out of date. Scroll down for Devin Review's latest report on this PR.
Devin Review found 0 new potential issues.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Manage named concurrency limits at runtime: list and retrieve report
each limit's bounds plus its live running and queued counts, override
changes only the given bounds (total zero pauses the limit), and reset
restores the declared values.
This comment was marked as resolved.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
…ting
Matches the SDK's trigger validation, and the shared changeset now
versions react-hooks alongside sdk and core.
matt-aitken
changed the title
feat(sdk,core,webapp,run-engine): declare queue gates on tasks and triggers
feat(sdk,core,webapp,run-engine): task concurrency option and shareable named limits
Sep 7, 2026
The index step collected concurrencyLimits into the worker manifest, but both
the dev session and the deploy index controller dropped the field when building
the create-background-worker request, so declared named limits registered with
no bounds and were never enforced.
|
Closing: this stack was flattened into a single change that has now been merged and will land in this repository via the automated sync. All review feedback from these PRs is incorporated, along with further review rounds on the flattened change.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
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.
|