Skip to content

Commit

Permalink
fix: don't crash when tail event is null
Browse files Browse the repository at this point in the history
Sometime the "event" on a tail can be null. This patch makes sure we don't crash when that happens. Fixes #918
  • Loading branch information
threepointone committed May 7, 2022
1 parent 94d3d6d commit cf22822
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 20 deletions.
7 changes: 7 additions & 0 deletions .changeset/khaki-starfishes-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

fix: don't crash when tail event is null

Sometime the "event" on a tail can be null. This patch makes sure we don't crash when that happens. Fixes https://github.com/cloudflare/wrangler2/issues/918
58 changes: 44 additions & 14 deletions packages/wrangler/src/__tests__/tail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,31 @@ describe("tail", () => {
`);
});

it("should not crash when the tail message has a void event", async () => {
const api = mockWebsocketAPIs();
await runWrangler("tail test-worker --format pretty");

const message = generateMockEventMessage({ event: null });
const serializedMessage = serialize(message);

api.ws.send(serializedMessage);
expect(
std.out
.replace(
new Date(mockEventTimestamp).toLocaleString(),
"[mock timestamp string]"
)
.replace(
mockTailExpiration.toLocaleString(),
"[mock expiration date]"
)
).toMatchInlineSnapshot(`
"Successfully created tail, expires at [mock expiration date]
Connected to test-worker, waiting for logs...
[missing request] - Ok @ [mock timestamp string]"
`);
});

it("defaults to logging in pretty format when the output is a TTY", async () => {
setIsTTY(true);
const api = mockWebsocketAPIs();
Expand Down Expand Up @@ -414,17 +439,18 @@ function serialize(message: TailEventMessage): WebSocket.RawData {
// This isn't a problem outside of testing since deserialization
// works just fine and wrangler never _sends_ any event messages,
// it only receives them.
const request = (message.event as RequestEvent).request;
const request = ((message.event as RequestEvent | undefined | null) || {})
.request;
const stringified = JSON.stringify(message, (key, value) => {
if (key !== "request") {
return value;
}

return {
...request,
url: request.url,
headers: request.headers,
method: request.method,
url: request?.url,
headers: request?.headers,
method: request?.method,
};
});

Expand All @@ -439,9 +465,9 @@ function serialize(message: TailEventMessage): WebSocket.RawData {
* @returns whether event is a ScheduledEvent (true) or a RequestEvent
*/
function isScheduled(
event: ScheduledEvent | RequestEvent
event: ScheduledEvent | RequestEvent | undefined | null
): event is ScheduledEvent {
return "cron" in event;
return Boolean(event && "cron" in event);
}

/**
Expand Down Expand Up @@ -607,15 +633,19 @@ function mockWebsocketAPIs(env?: string, legacyEnv = false): MockAPI {
* @param opts Any specific parts of the message to use instead of defaults
* @returns a `TailEventMessage` that wrangler can process and display
*/
function generateMockEventMessage(
opts?: Partial<TailEventMessage>
): TailEventMessage {
function generateMockEventMessage({
outcome = "ok",
exceptions = [],
logs = [],
eventTimestamp = mockEventTimestamp,
event = generateMockRequestEvent(),
}: Partial<TailEventMessage>): TailEventMessage {
return {
outcome: opts?.outcome || "ok",
exceptions: opts?.exceptions || [],
logs: opts?.logs || [],
eventTimestamp: opts?.eventTimestamp || mockEventTimestamp,
event: opts?.event || generateMockRequestEvent(),
outcome,
exceptions,
logs,
eventTimestamp,
event,
};
}

Expand Down
2 changes: 1 addition & 1 deletion packages/wrangler/src/tail/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export type TailEventMessage = {
* Until workers-types exposes individual types for export, we'll have
* to just re-define these types ourselves.
*/
event: RequestEvent | ScheduledEvent;
event: RequestEvent | ScheduledEvent | undefined | null;
};

/**
Expand Down
14 changes: 9 additions & 5 deletions packages/wrangler/src/tail/printing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ export function prettyPrintLogs(data: WebSocket.RawData): void {

logger.log(`"${cronPattern}" @ ${datetime} - ${outcome}`);
} else {
const requestMethod = eventMessage.event.request.method.toUpperCase();
const url = eventMessage.event.request.url;
const requestMethod = eventMessage.event?.request.method.toUpperCase();
const url = eventMessage.event?.request.url;
const outcome = prettifyOutcome(eventMessage.outcome);
const datetime = new Date(eventMessage.eventTimestamp).toLocaleString();

logger.log(`${requestMethod} ${url} - ${outcome} @ ${datetime}`);
logger.log(
url
? `${requestMethod} ${url} - ${outcome} @ ${datetime}`
: `[missing request] - ${outcome} @ ${datetime}`
);
}

if (eventMessage.logs.length > 0) {
Expand All @@ -41,9 +45,9 @@ export function jsonPrintLogs(data: WebSocket.RawData): void {
}

function isScheduledEvent(
event: RequestEvent | ScheduledEvent
event: RequestEvent | ScheduledEvent | undefined | null
): event is ScheduledEvent {
return "cron" in event;
return Boolean(event && "cron" in event);
}

function prettifyOutcome(outcome: Outcome): string {
Expand Down

0 comments on commit cf22822

Please sign in to comment.