Skip to content

Commit d936ab3

Browse files
committed
fix(webapp): avoid scheduled test page crash on empty payloads
Harden scheduled run payload parsing to handle empty/malformed packets without throwing, and add a regression test. Made-with: Cursor
1 parent def21b2 commit d936ab3

File tree

4 files changed

+75
-9
lines changed

4 files changed

+75
-9
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
area: webapp
3+
type: fix
4+
---
5+
6+
Prevent scheduled task test page crashes when prior runs have empty payloads
7+

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

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ClickHouse } from "@internal/clickhouse";
2-
import { ScheduledTaskPayload, parsePacket, prettyPrintPacket } from "@trigger.dev/core/v3";
2+
import { parsePacket, prettyPrintPacket } from "@trigger.dev/core/v3";
33
import {
44
type RuntimeEnvironmentType,
55
type TaskRunStatus,
@@ -13,6 +13,7 @@ import { RunsRepository } from "~/services/runsRepository/runsRepository.server"
1313
import { getTimezones } from "~/utils/timezones.server";
1414
import { findCurrentWorkerDeployment } from "~/v3/models/workerDeployment.server";
1515
import { queueTypeFromType } from "./QueueRetrievePresenter.server";
16+
import { getScheduleTaskRunPayload } from "./getScheduleTaskRunPayload.server";
1617

1718
export type RunTemplate = TaskRunTemplate & {
1819
scheduledTaskPayload?: ScheduledRun["payload"];
@@ -380,11 +381,3 @@ export class TestTaskPresenter {
380381
}
381382
}
382383

383-
async function getScheduleTaskRunPayload(payload: string, payloadType: string) {
384-
const packet = await parsePacket({ data: payload, dataType: payloadType });
385-
if (!packet.timezone) {
386-
packet.timezone = "UTC";
387-
}
388-
const parsed = ScheduledTaskPayload.safeParse(packet);
389-
return parsed;
390-
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ScheduledTaskPayload, parsePacket } from "@trigger.dev/core/v3";
2+
3+
export async function getScheduleTaskRunPayload(payload: string, payloadType: string) {
4+
let packet: unknown;
5+
6+
try {
7+
packet = await parsePacket({ data: payload, dataType: payloadType });
8+
} catch {
9+
packet = undefined;
10+
}
11+
12+
if (packet && typeof packet === "object" && !Array.isArray(packet)) {
13+
const maybeTimezone = (packet as { timezone?: unknown }).timezone;
14+
15+
if (typeof maybeTimezone !== "string" || maybeTimezone.length === 0) {
16+
(packet as { timezone: string }).timezone = "UTC";
17+
}
18+
}
19+
20+
return ScheduledTaskPayload.safeParse(packet);
21+
}
22+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { describe, it, expect } from "vitest";
2+
import superjson from "superjson";
3+
import { getScheduleTaskRunPayload } from "../app/presenters/v3/getScheduleTaskRunPayload.server";
4+
5+
describe("getScheduleTaskRunPayload", () => {
6+
it("should return failure when payload is empty", async () => {
7+
const result = await getScheduleTaskRunPayload("", "application/json");
8+
9+
expect(result.success).toBe(false);
10+
if (!result.success) {
11+
expect(result.error).toBeDefined();
12+
}
13+
});
14+
15+
it("should parse a valid scheduled payload", async () => {
16+
const now = new Date();
17+
const result = await getScheduleTaskRunPayload(
18+
superjson.stringify({
19+
scheduleId: "sch_123",
20+
type: "DECLARATIVE",
21+
timestamp: now,
22+
timezone: "UTC",
23+
upcoming: [now],
24+
}),
25+
"application/super+json"
26+
);
27+
28+
expect(result.success).toBe(true);
29+
if (result.success) {
30+
expect(result.data.scheduleId).toBe("sch_123");
31+
expect(result.data.type).toBe("DECLARATIVE");
32+
expect(result.data.timezone).toBe("UTC");
33+
expect(result.data.upcoming.length).toBe(1);
34+
expect(result.data.timestamp).toBeInstanceOf(Date);
35+
}
36+
});
37+
38+
it("should return failure for invalid JSON", async () => {
39+
const result = await getScheduleTaskRunPayload("{invalid", "application/json");
40+
41+
expect(result.success).toBe(false);
42+
});
43+
});
44+

0 commit comments

Comments
 (0)