You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit ee5e5da
Browse filesBrowse the repository at this point in the historyBrowse files
feat(convex): on-demand run synchronization to the integration
Add on-demand synchronization to `@trigger.dev/convex` with
`trigger.refresh(ctx, componentRunId)`.
Applications can use Trigger Realtime for responsive progress, then
request an earlier authoritative status check when Realtime reports
completion. The component keeps its existing polling and watchdog as
recovery when no browser is connected.
- Refresh requests are scheduled asynchronously and coalesced per run.
- Refresh-driven status checks start at least five seconds after the
previous status check. Hints during an in-flight request queue one
follow-up without discarding that response.
- Pending submissions, paused synchronization, and completed records are
no-ops. Refresh does not trigger another task, reset retry failures, or
resume paused work.
- Existing terminal-state handling, transactional completion callbacks,
output budgets, generation fencing, and request/credential cleanup are
reused.
- Optional internal coordination fields require no record migration and
are excluded from the public run shape.
- README guidance includes an ownership-checked mutation, the
Realtime/polling split, and the warning that Realtime column exclusions
do not prevent a run-read token from retrieving payloads through REST.
No Trigger server changes, persistent subscriptions, new dependencies,
or token-issuing API are added.
Mono-RevId: 91a3884a75fe0972740ee42cd6094a82ae036c63
Add `trigger.refresh(ctx, id)` to request an earlier status check for a Convex-tracked run, so applications using Trigger Realtime can publish results without waiting for the next scheduled poll. Requests are coalesced and rate-limited, use the existing completion callback, and retain polling as a recovery fallback.
Copy file name to clipboardExpand all lines: packages/convex/README.md
+30Lines changed: 30 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -124,6 +124,7 @@ The ID returned by `trigger.trigger` identifies the **component record**, not th
124
124
-`trigger(ctx, taskId, payload, options?)`: enqueue work. Calling from a mutation makes the request atomic with your application's writes.
125
125
-`getRun(ctx, id)`: read one record reactively.
126
126
-`listRuns(ctx, paginationOpts)`: paginate records, newest first, up to 100 per page and a bounded read budget.
127
+
-`refresh(ctx, id)`: schedule an earlier status check for an active, submitted run. Returns `null` after scheduling, not the updated run.
127
128
-`resume(ctx, id)`: resume paused synchronization using the current credentials.
128
129
129
130
Trigger options include tags, delay, queue name, concurrency key, machine, metadata, max attempts, max duration, TTL, and a component-level idempotency key.
@@ -134,6 +135,35 @@ The constructor accepts `secretKey` (defaults to `TRIGGER_SECRET_KEY`), `baseUrl
134
135
135
136
**Authorization belongs in your application's functions.** The component has no tenant or user model. Do not expose arbitrary record IDs or `listRuns` to clients without enforcing ownership. Queries never return stored credentials or request payloads.
136
137
138
+
## Realtime progress and faster result delivery
139
+
140
+
Use [Trigger Realtime](https://trigger.dev/docs/realtime/overview) for responsive browser progress, and Convex queries for durable application state. When Realtime reports that a run is complete, call an ownership-checked application mutation that requests a component refresh:
141
+
142
+
```ts
143
+
// convex/jobs.ts
144
+
exportconst refresh =mutation({
145
+
args: { jobId: v.id("jobs") },
146
+
handler: async (ctx, { jobId }) => {
147
+
const user =awaitctx.auth.getUserIdentity();
148
+
const job =awaitctx.db.get(jobId);
149
+
if (!user||!job||job.owner!==user.subject) thrownewError("Unauthorized");
150
+
if (job.runId) awaittrigger.refresh(ctx, job.runId);
151
+
},
152
+
});
153
+
```
154
+
155
+
Pass the component record ID to `refresh`, not the remote Trigger run ID. Your browser subscribes to the latter, available as `run.runId` from `getRun`.
156
+
157
+
A refresh is only a hint: the component retrieves status and output directly from Trigger and uses the same validation, completion callback, and credential cleanup as normal polling. It never accepts client-supplied status or output. Observe `getRun` or your application query for the persisted result; awaiting `refresh` does not wait for that result.
158
+
159
+
- Refresh requests are coalesced per run. Status checks requested this way start at least five seconds after the previous status check.
160
+
- A hint received during a check queues one follow-up instead of interrupting or discarding the in-flight response. If that response completes the run, no follow-up is needed.
161
+
- Pending submissions, paused synchronization, and completed records are no-ops. Refresh never submits a task or resumes paused work; use `resume` after repairing a paused synchronization.
162
+
- Call refresh when Realtime observes completion, including an already-completed run after reconnecting. Do not call it on every metadata update to animate progress.
163
+
- Scheduled polling and its watchdog remain enabled. Convex can still finish the run if the browser closes, the subscription disconnects, or the refresh request fails. No persistent subscription inside a Convex action is required.
164
+
165
+
**Realtime token safety:** authenticate the token request, verify job ownership, and issue a short-lived token scoped to the exact remote run. Keep the root Trigger key server-side. A run-read token can also read the run through REST, including its payload; Realtime `skipColumns` is not a restriction on REST access. Keep worker credentials, storage-upload capabilities, and other secrets out of token-readable payloads, outputs, metadata, and errors. Application mutations must enforce ownership even when component refreshes are coalesced.
166
+
137
167
## Execution and reliability
138
168
139
169
1. The calling mutation writes a component record and schedules submission. If the transaction rolls back, neither survives.
0 commit comments