Skip to content

Commit 319e3b9

Browse files
isshaddadTrigger.dev RepoOps
authored andcommitted
docs: correct concurrency limits, error group alerts, TTL vs delay, and pending version
Four docs corrections, one per commit. **Concurrency limits** (`limits.mdx`) — the table published a single headline figure per tier, flattened from the four per-environment values a plan actually sets, and drifted from the current defaults. Now split per environment, with a note that the dashboard Concurrency page is authoritative because the enforced limit also includes purchased add-on and manual concurrency. **Error group alerts** (`troubleshooting-alerts.mdx`) — undocumented until now. They are created from the Errors page, appear in the Alerts table, and are issue-based: they fire on a new issue, a regression or an unignore, and a group that has alerted latches to Unresolved and stays quiet. People configure one expecting a notification per failed run and get silence. Documents the firing rules, the quiet steady state, and which alert type to pick for "tell me about every failed run". Also adds the `alert.error` webhook, which the reference omitted. **Maximum run TTL** (`limits.mdx`) — "all runs have an enforced maximum TTL of 14 days" reads as a cap on how far ahead you can schedule. It isn't: a delayed run arms no TTL expiry, and the TTL clock starts when the delay elapses. Also states that `delay` has no upper bound. **Pending version** (`troubleshooting.mdx`) — a new troubleshooting entry. A run parks here when the version deployed to that environment carries neither the run's task nor its queue. Lists the four causes seen in support: task missing from the deployed version, a queue no deployed task declares, triggering into the wrong org/project/environment, and a later deploy removing or renaming the task or queue while the run was waiting. Also covers runs parked by version skew protection, which wait for their specific external deployment id and expire after 1 hour. Docs only. Mono-RevId: c8a80f8c46ff160ac72fc7c1a1ef5f88a0b02f2c
1 parent f8babdf commit 319e3b9

3 files changed

Lines changed: 152 additions & 7 deletions

File tree

‎docs/limits.mdx‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ You can view your current limits, quotas, and rate limit usage in real-time by v
1414

1515
## Concurrency limits
1616

17-
| Pricing tier | Limit |
18-
| :----------- | :------------------- |
19-
| Free | 10 concurrent runs |
20-
| Hobby | 25 concurrent runs |
21-
| Pro | 100+ concurrent runs |
17+
Concurrency is allocated **per environment**, not as a single figure for the whole organization. Each plan sets a separate default for production, staging, preview and development:
18+
19+
| Pricing tier | Production | Staging | Preview | Development |
20+
| :----------- | :--------- | :------ | :------ | :---------- |
21+
| Free | 20 | 10 | 10 | 25 |
22+
| Hobby | 50 | 25 | 25 | 25 |
23+
| Pro | 200+ | 100 | 100 | 25 |
24+
25+
These are plan defaults. The limit actually enforced for one of your environments can be higher: purchased add-on concurrency and any manual increase we have applied are both included in it. The **Concurrency** page in the dashboard (left sidebar) is authoritative for your organization — if it disagrees with the table above, the dashboard is correct.
2226

2327
Extra concurrency above the Pro tier limit is available via the dashboard. Click the "Concurrency" page from the left sidebar when on the Pro plan to purchase more.
2428

@@ -50,7 +54,13 @@ The maximum number of runs that can be queued **per queue** (not across all queu
5054

5155
## Maximum run TTL
5256

53-
On Trigger.dev Cloud, all runs have an enforced maximum TTL of 14 days. Runs without an explicit TTL automatically receive the 14-day TTL; runs with a TTL longer than 14 days are clamped to 14 days. This prevents queued runs from accumulating indefinitely. If you self-host, you can configure a maximum TTL via the `RUN_ENGINE_DEFAULT_MAX_TTL` environment variable — see [Self-hosting environment variables](/self-hosting/env/webapp#run-engine).
57+
On Trigger.dev Cloud, all runs have an enforced maximum TTL of 14 days. Runs without an explicit TTL automatically receive the 14-day TTL; runs with a TTL longer than 14 days are clamped to 14 days. This prevents queued runs from accumulating indefinitely.
58+
59+
**The TTL cap does not limit how far ahead you can schedule a run.** TTL governs how long a run may sit *queued* waiting for a concurrency slot. A run triggered with [`delay`](/triggering#delay) is not queued while it is delayed, and no TTL expiry is armed for it — the TTL clock only starts once the delay elapses and the run is enqueued. So scheduling a run a month out with `delay` works fine, and the 14 days then applies to how long it may wait for a slot after that month is up.
60+
61+
There is no maximum on `delay`.
62+
63+
If you self-host, you can configure a maximum TTL via the `RUN_ENGINE_DEFAULT_MAX_TTL` environment variable — see [Self-hosting environment variables](/self-hosting/env/webapp#run-engine).
5464

5565
## Schedules
5666

‎docs/troubleshooting-alerts.mdx‎

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ We support receiving alerts for the following events:
77
- Run fails
88
- Deployment fails
99
- Deployment succeeds
10+
- A new error group appears, regresses, or is unignored
11+
12+
The first three are created from the **Alerts** page. The fourth — an **Error group** alert — is created from the **Errors** page instead, but appears in the same Alerts table once created. It behaves quite differently from a run failure alert; see [Error group alerts](#error-group-alerts) below.
13+
14+
<Note>
15+
If you want to be told about **every** run that fails, choose a **run fails** alert. An Error group
16+
alert will not do this — it deliberately stays quiet once it has alerted on a given error.
17+
</Note>
1018

1119
## How to setup alerts
1220

@@ -36,6 +44,37 @@ Click on the triple dot menu on the right side of the table row and select "Disa
3644
</Steps>
3745

3846

47+
## Error group alerts
48+
49+
Error group alerts are **issue-based**, not run-based. They are created from the **Errors** page in the dashboard (the "Configure alerts…" button), not from the New alert modal on the Alerts page. Once created they show up in the Alerts table alongside your other alerts, labelled "Error group".
50+
51+
An error group is one distinct error — the same error from many runs is a single group, with a status of **Unresolved**, **Resolved** or **Ignored** that you set from the Errors page.
52+
53+
### When an error group alert fires
54+
55+
The alert only fires when a group's status *changes* in one of these three ways:
56+
57+
| Trigger | Meaning |
58+
| :------ | :------ |
59+
| New issue | The error has been seen for the first time. |
60+
| Regression | The group was marked **Resolved**, and the error has occurred again since. |
61+
| Unignored | The group was **Ignored**, and the ignore condition you set has been breached. |
62+
63+
### Why it goes quiet
64+
65+
This is the part that surprises people, so it is worth stating plainly:
66+
67+
**An Unresolved error group does not alert.** After an error group alert fires, the group is set to Unresolved, and it stays silent no matter how many more times that error occurs. It will only alert again once you mark it **Resolved** (and it then recurs) or **Ignored** (and the ignore condition is breached).
68+
69+
This is intentional — one persistently broken task should not flood your Slack channel with a message per failed run. But it means an Error group alert is not a substitute for a run failure alert. If a task has been failing in production for days and you have had no notification, check whether the only alert you have configured is an Error group alert whose group is sitting at Unresolved.
70+
71+
### Which alert type should I use?
72+
73+
- **"Tell me about every run that fails"** → a **run fails** alert, from the Alerts page. It fires for every run that fails once its retries are exhausted.
74+
- **"Tell me when something new breaks"** → an **Error group** alert, from the Errors page.
75+
76+
The two are complementary, and many teams want both.
77+
3978
## Alert webhooks
4079

4180
For the alert webhooks you can use the SDK to parse them. Here is an example of how to parse the webhook payload in Remix:
@@ -69,6 +108,10 @@ export async function action({ request }: ActionFunctionArgs) {
69108
console.log("[Webhook Internal Test] Deployment failed alert webhook received", { event });
70109
break;
71110
}
111+
case "alert.error": {
112+
console.log("[Webhook Internal Test] Error group alert webhook received", { event });
113+
break;
114+
}
72115
default: {
73116
console.log("[Webhook Internal Test] Unhandled webhook type", { event });
74117
}
@@ -112,7 +155,7 @@ When you create a webhook alert, you'll receive different payloads depending on
112155
</ParamField>
113156

114157
<ParamField path="type" type="string">
115-
The type of alert webhook. One of: `alert.run.failed`, `alert.deployment.success`, or `alert.deployment.failed`
158+
The type of alert webhook. One of: `alert.run.failed`, `alert.deployment.success`, `alert.deployment.failed`, or `alert.error`
116159
</ParamField>
117160

118161
### Run Failed Alert
@@ -383,3 +426,83 @@ This webhook is sent when a deployment fails. The payload is available on the `o
383426
Project name
384427
</ParamField>
385428

429+
430+
### Error Group Alert
431+
432+
This webhook is sent for an [error group alert](#error-group-alerts). The payload is available on the `object` property:
433+
434+
<ParamField path="object.classification" type="string">
435+
Why the alert fired. One of: `new_issue`, `regression`, `unignored`
436+
</ParamField>
437+
438+
<ParamField path="object.error.fingerprint" type="string">
439+
Identifier for the error group
440+
</ParamField>
441+
442+
<ParamField path="object.error.type" type="string">
443+
Error type
444+
</ParamField>
445+
446+
<ParamField path="object.error.message" type="string">
447+
Error message
448+
</ParamField>
449+
450+
<ParamField path="object.error.stackTrace" type="string">
451+
Sample stack trace, if available
452+
</ParamField>
453+
454+
<ParamField path="object.error.firstSeen" type="string">
455+
When the error was first seen
456+
</ParamField>
457+
458+
<ParamField path="object.error.lastSeen" type="string">
459+
When the error was last seen
460+
</ParamField>
461+
462+
<ParamField path="object.error.occurrenceCount" type="number">
463+
Number of occurrences
464+
</ParamField>
465+
466+
<ParamField path="object.error.taskIdentifier" type="string">
467+
Task the error occurred in
468+
</ParamField>
469+
470+
<ParamField path="object.environment.id" type="string">
471+
Environment ID
472+
</ParamField>
473+
474+
<ParamField path="object.environment.name" type="string">
475+
Environment name
476+
</ParamField>
477+
478+
<ParamField path="object.organization.id" type="string">
479+
Organization ID
480+
</ParamField>
481+
482+
<ParamField path="object.organization.slug" type="string">
483+
Organization slug
484+
</ParamField>
485+
486+
<ParamField path="object.organization.name" type="string">
487+
Organization name
488+
</ParamField>
489+
490+
<ParamField path="object.project.id" type="string">
491+
Project ID
492+
</ParamField>
493+
494+
<ParamField path="object.project.ref" type="string">
495+
Project reference
496+
</ParamField>
497+
498+
<ParamField path="object.project.slug" type="string">
499+
Project slug
500+
</ParamField>
501+
502+
<ParamField path="object.project.name" type="string">
503+
Project name
504+
</ParamField>
505+
506+
<ParamField path="object.dashboardUrl" type="string">
507+
URL to view the error in the dashboard
508+
</ParamField>

‎docs/troubleshooting.mdx‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ You need to be on at least these minor versions:
163163

164164
## Runtime issues
165165

166+
### Runs stuck in "Pending version"
167+
168+
A run sits in **Pending version** when the version deployed to that environment doesn't contain the run's task, or doesn't contain the queue it was triggered on. The run isn't lost: unless it's pinned to a specific deployment (see the last cause below), it starts automatically once a version containing both is deployed.
169+
170+
Usually one of:
171+
172+
- **The task isn't in the deployed version.** It was renamed or removed, or the deploy adding it hasn't landed yet. Check the Tasks page for that environment.
173+
- **The queue doesn't exist in the deployed version.** Overriding `queue` at trigger time only works if a deployed task declares that queue — see [Queues](/queues).
174+
- **You triggered into the wrong organization, project or environment.** Check the secret key you triggered with belongs to the same place you deployed to.
175+
- **A later deploy removed or renamed the task or queue while the run was waiting.** Most likely with `delay`. Pin the run to a version to avoid this: `trigger(payload, { delay: "1h", version: "20260227.2" })`. See [atomic deployments](/deployment/atomic-deployment).
176+
- **The run is pinned to an external deployment id that hasn't arrived.** This is [version skew protection](/deployment/version-skew-protection#waiting-and-expiry), and it behaves differently: only a deployment carrying the matching id releases the run, and it expires after 1 hour if none does.
177+
166178
### `Environment variable not found:`
167179

168180
Your code is deployed separately from the rest of your app(s) so you need to make sure that you set any environment variables you use in your tasks in the Trigger.dev dashboard. [Read the guide](/deploy-environment-variables).

0 commit comments

Comments
 (0)