Skip to content

Commit ba141be

Browse files
authored
Merge branch 'main' into feat(webapp)-auto-app-logout
2 parents b768149 + 7c7d785 commit ba141be

22 files changed

Lines changed: 927 additions & 151 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trigger.dev": patch
3+
---
4+
5+
Add `--no-browser` flag to `init` and `login` to skip auto-opening the browser during authentication. Also error loudly when `init` is run without `--yes` under non-TTY stdin (previously default-and-exited silently, leaving the project half-initialized). Both commands now show an `Examples` section in `--help`.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/core": patch
3+
---
4+
5+
Redact the `resolveWaitpoint` runtime log so it only emits `id` and `type` instead of the full completed waitpoint. Previously the log printed the entire waitpoint (including `output`) to stdout in production runs, which could leak sensitive payloads. The value returned by `wait.forToken()` is unchanged.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: improvement
4+
---
5+
6+
Stop writing per-tick state (`lastScheduledTimestamp`, `nextScheduledTimestamp`, `lastRunTriggeredAt`) on `TaskSchedule` and `TaskScheduleInstance`. The schedule engine now carries the previous fire time forward via the worker queue payload, eliminating ~270K dead-tuple-driven autovacuums per year on these hot tables and the associated `IO:XactSync` mini-spikes on the writer. Customer-facing `payload.lastTimestamp` semantics are unchanged.

apps/webapp/app/presenters/v3/ScheduleListPresenter.server.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import { getLimit } from "~/services/platform.v3.server";
66
import { findCurrentWorkerFromEnvironment } from "~/v3/models/workerDeployment.server";
77
import { ServiceValidationError } from "~/v3/services/baseService.server";
88
import { CheckScheduleService } from "~/v3/services/checkSchedule.server";
9-
import { calculateNextScheduledTimestampFromNow } from "~/v3/utils/calculateNextSchedule.server";
9+
import {
10+
calculateNextScheduledTimestampFromNow,
11+
previousScheduledTimestamp,
12+
} from "~/v3/utils/calculateNextSchedule.server";
1013
import { BasePresenter } from "./basePresenter.server";
1114

1215
type ScheduleListOptions = {
@@ -193,8 +196,8 @@ export class ScheduleListPresenter extends BasePresenter {
193196
},
194197
},
195198
active: true,
196-
lastRunTriggeredAt: true,
197199
createdAt: true,
200+
updatedAt: true,
198201
},
199202
where: {
200203
projectId: project.id,
@@ -244,6 +247,29 @@ export class ScheduleListPresenter extends BasePresenter {
244247
});
245248

246249
const schedules: ScheduleListItem[] = rawSchedules.map((schedule) => {
250+
// Approximate "last run" from the cron's previous slot. Skip inactive
251+
// schedules — the cron's previous slot reflects what *would* have
252+
// fired, but a deactivated schedule didn't actually fire there. Skip
253+
// when the cron's previous slot predates `updatedAt`: any config
254+
// change (cron edited, timezone changed, deactivate/reactivate)
255+
// bumps updatedAt, and a slot from before the most recent change
256+
// didn't fire under the current configuration. cron-parser throws
257+
// on malformed expressions, so degrade to undefined per-row rather
258+
// than failing the whole list. UI is best-effort; the runs page is
259+
// the source of truth.
260+
let lastRun: Date | undefined;
261+
if (schedule.active) {
262+
try {
263+
const cronPrev = previousScheduledTimestamp(
264+
schedule.generatorExpression,
265+
schedule.timezone
266+
);
267+
lastRun = cronPrev.getTime() > schedule.updatedAt.getTime() ? cronPrev : undefined;
268+
} catch {
269+
lastRun = undefined;
270+
}
271+
}
272+
247273
return {
248274
id: schedule.id,
249275
type: schedule.type,
@@ -256,7 +282,7 @@ export class ScheduleListPresenter extends BasePresenter {
256282
timezone: schedule.timezone,
257283
active: schedule.active,
258284
externalId: schedule.externalId,
259-
lastRun: schedule.lastRunTriggeredAt ?? undefined,
285+
lastRun,
260286
nextRun: calculateNextScheduledTimestampFromNow(
261287
schedule.generatorExpression,
262288
schedule.timezone

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.errors._index/route.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ function ErrorActivityGraph({ activity }: { activity: ErrorOccurrenceActivity })
708708
</ResponsiveContainer>
709709
</div>
710710
<SimpleTooltip
711+
asChild
711712
button={
712713
<span className="-mt-1 text-xxs tabular-nums text-text-dimmed">
713714
{formatNumberCompact(maxCount)}

apps/webapp/app/v3/utils/calculateNextSchedule.server.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ function calculateNextStep(schedule: string, timezone: string | null, currentDat
2222
.toDate();
2323
}
2424

25+
export function previousScheduledTimestamp(
26+
schedule: string,
27+
timezone: string | null,
28+
fromTimestamp: Date = new Date()
29+
) {
30+
return parseExpression(schedule, {
31+
currentDate: fromTimestamp,
32+
utc: timezone === null,
33+
tz: timezone ?? undefined,
34+
})
35+
.prev()
36+
.toDate();
37+
}
38+
2539
export function nextScheduledTimestamps(
2640
cron: string,
2741
timezone: string | null,

internal-packages/database/prisma/schema.prisma

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,6 +2137,7 @@ model TaskSchedule {
21372137
///Instances of the schedule that are active
21382138
instances TaskScheduleInstance[]
21392139
2140+
/// @deprecated stop writing 2026-04-30; reads moved out of code (UI now derives from cron's previous slot). Drop in follow-up.
21402141
lastRunTriggeredAt DateTime?
21412142
21422143
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
@@ -2182,7 +2183,9 @@ model TaskScheduleInstance {
21822183
21832184
active Boolean @default(true)
21842185
2186+
/// @deprecated stop writing 2026-04-30; engine derives from cron + exactScheduleTime. Drop in follow-up.
21852187
lastScheduledTimestamp DateTime?
2188+
/// @deprecated stop writing 2026-04-30; engine derives from cron + now(). Drop in follow-up.
21862189
nextScheduledTimestamp DateTime?
21872190
21882191
//you can only have a schedule attached to each environment once

0 commit comments

Comments
 (0)