Skip to content

Commit f4e3b5b

Browse files
committed
chore(runner): explicitly stringify tunnel messages, commands, and events
1 parent d5276a3 commit f4e3b5b

File tree

3 files changed

+201
-12
lines changed

3 files changed

+201
-12
lines changed

engine/sdks/typescript/runner/src/mod.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as protocol from "@rivetkit/engine-runner-protocol";
22
import type { Logger } from "pino";
33
import type WebSocket from "ws";
44
import { logger, setLogger } from "./log.js";
5+
import { stringifyCommandWrapper, stringifyEvent } from "./stringify";
56
import { Tunnel } from "./tunnel";
67
import {
78
calculateBackoff,
@@ -754,7 +755,7 @@ export class Runner {
754755
for (const commandWrapper of commands) {
755756
this.log?.info({
756757
msg: "received command",
757-
commandWrapper,
758+
command: stringifyCommandWrapper(commandWrapper),
758759
});
759760
if (commandWrapper.inner.tag === "CommandStartActor") {
760761
this.#handleCommandStartActor(commandWrapper);
@@ -905,9 +906,8 @@ export class Runner {
905906

906907
this.log?.info({
907908
msg: "sending event to server",
908-
index: eventWrapper.index,
909-
tag: eventWrapper.inner.tag,
910-
val: eventWrapper.inner.val,
909+
event: stringifyEvent(eventWrapper.inner),
910+
index: eventWrapper.index.toString(),
911911
});
912912

913913
this.__sendToServer({
@@ -962,9 +962,8 @@ export class Runner {
962962

963963
this.log?.info({
964964
msg: "sending event to server",
965-
index: eventWrapper.index,
966-
tag: eventWrapper.inner.tag,
967-
val: eventWrapper.inner.val,
965+
event: stringifyEvent(eventWrapper.inner),
966+
index: eventWrapper.index.toString(),
968967
});
969968

970969
this.__sendToServer({
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import type * as protocol from "@rivetkit/engine-runner-protocol";
2+
3+
/**
4+
* Helper function to stringify ArrayBuffer for logging
5+
*/
6+
function stringifyArrayBuffer(buffer: ArrayBuffer): string {
7+
return `ArrayBuffer(${buffer.byteLength})`;
8+
}
9+
10+
/**
11+
* Helper function to stringify bigint for logging
12+
*/
13+
function stringifyBigInt(value: bigint): string {
14+
return `${value}n`;
15+
}
16+
17+
/**
18+
* Helper function to stringify Map for logging
19+
*/
20+
function stringifyMap(map: ReadonlyMap<string, string>): string {
21+
const entries = Array.from(map.entries())
22+
.map(([k, v]) => `"${k}": "${v}"`)
23+
.join(", ");
24+
return `Map(${map.size}){${entries}}`;
25+
}
26+
27+
/**
28+
* Stringify ToServerTunnelMessageKind for logging
29+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
30+
*/
31+
export function stringifyToServerTunnelMessageKind(
32+
kind: protocol.ToServerTunnelMessageKind,
33+
): string {
34+
switch (kind.tag) {
35+
case "TunnelAck":
36+
return "TunnelAck";
37+
case "ToServerResponseStart": {
38+
const { status, headers, body, stream } = kind.val;
39+
const bodyStr = body === null ? "null" : stringifyArrayBuffer(body);
40+
return `ToServerResponseStart{status: ${status}, headers: ${stringifyMap(headers)}, body: ${bodyStr}, stream: ${stream}}`;
41+
}
42+
case "ToServerResponseChunk": {
43+
const { body, finish } = kind.val;
44+
return `ToServerResponseChunk{body: ${stringifyArrayBuffer(body)}, finish: ${finish}}`;
45+
}
46+
case "ToServerResponseAbort":
47+
return "ToServerResponseAbort";
48+
case "ToServerWebSocketOpen": {
49+
const { canHibernate, lastMsgIndex } = kind.val;
50+
return `ToServerWebSocketOpen{canHibernate: ${canHibernate}, lastMsgIndex: ${stringifyBigInt(lastMsgIndex)}}`;
51+
}
52+
case "ToServerWebSocketMessage": {
53+
const { data, binary } = kind.val;
54+
return `ToServerWebSocketMessage{data: ${stringifyArrayBuffer(data)}, binary: ${binary}}`;
55+
}
56+
case "ToServerWebSocketMessageAck": {
57+
const { index } = kind.val;
58+
return `ToServerWebSocketMessageAck{index: ${index}}`;
59+
}
60+
case "ToServerWebSocketClose": {
61+
const { code, reason, retry } = kind.val;
62+
const codeStr = code === null ? "null" : code.toString();
63+
const reasonStr = reason === null ? "null" : `"${reason}"`;
64+
return `ToServerWebSocketClose{code: ${codeStr}, reason: ${reasonStr}, retry: ${retry}}`;
65+
}
66+
}
67+
}
68+
69+
/**
70+
* Stringify ToClientTunnelMessageKind for logging
71+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
72+
*/
73+
export function stringifyToClientTunnelMessageKind(
74+
kind: protocol.ToClientTunnelMessageKind,
75+
): string {
76+
switch (kind.tag) {
77+
case "TunnelAck":
78+
return "TunnelAck";
79+
case "ToClientRequestStart": {
80+
const { actorId, method, path, headers, body, stream } = kind.val;
81+
const bodyStr = body === null ? "null" : stringifyArrayBuffer(body);
82+
return `ToClientRequestStart{actorId: "${actorId}", method: "${method}", path: "${path}", headers: ${stringifyMap(headers)}, body: ${bodyStr}, stream: ${stream}}`;
83+
}
84+
case "ToClientRequestChunk": {
85+
const { body, finish } = kind.val;
86+
return `ToClientRequestChunk{body: ${stringifyArrayBuffer(body)}, finish: ${finish}}`;
87+
}
88+
case "ToClientRequestAbort":
89+
return "ToClientRequestAbort";
90+
case "ToClientWebSocketOpen": {
91+
const { actorId, path, headers } = kind.val;
92+
return `ToClientWebSocketOpen{actorId: "${actorId}", path: "${path}", headers: ${stringifyMap(headers)}}`;
93+
}
94+
case "ToClientWebSocketMessage": {
95+
const { index, data, binary } = kind.val;
96+
return `ToClientWebSocketMessage{index: ${index}, data: ${stringifyArrayBuffer(data)}, binary: ${binary}}`;
97+
}
98+
case "ToClientWebSocketClose": {
99+
const { code, reason } = kind.val;
100+
const codeStr = code === null ? "null" : code.toString();
101+
const reasonStr = reason === null ? "null" : `"${reason}"`;
102+
return `ToClientWebSocketClose{code: ${codeStr}, reason: ${reasonStr}}`;
103+
}
104+
}
105+
}
106+
107+
/**
108+
* Stringify Command for logging
109+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
110+
*/
111+
export function stringifyCommand(command: protocol.Command): string {
112+
switch (command.tag) {
113+
case "CommandStartActor": {
114+
const { actorId, generation, config } = command.val;
115+
const keyStr = config.key === null ? "null" : `"${config.key}"`;
116+
const inputStr =
117+
config.input === null
118+
? "null"
119+
: stringifyArrayBuffer(config.input);
120+
return `CommandStartActor{actorId: "${actorId}", generation: ${generation}, config: {name: "${config.name}", key: ${keyStr}, createTs: ${stringifyBigInt(config.createTs)}, input: ${inputStr}}}`;
121+
}
122+
case "CommandStopActor": {
123+
const { actorId, generation } = command.val;
124+
return `CommandStopActor{actorId: "${actorId}", generation: ${generation}}`;
125+
}
126+
}
127+
}
128+
129+
/**
130+
* Stringify CommandWrapper for logging
131+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
132+
*/
133+
export function stringifyCommandWrapper(
134+
wrapper: protocol.CommandWrapper,
135+
): string {
136+
return `CommandWrapper{index: ${stringifyBigInt(wrapper.index)}, inner: ${stringifyCommand(wrapper.inner)}}`;
137+
}
138+
139+
/**
140+
* Stringify Event for logging
141+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
142+
*/
143+
export function stringifyEvent(event: protocol.Event): string {
144+
switch (event.tag) {
145+
case "EventActorIntent": {
146+
const { actorId, generation, intent } = event.val;
147+
const intentStr =
148+
intent.tag === "ActorIntentSleep"
149+
? "Sleep"
150+
: intent.tag === "ActorIntentStop"
151+
? "Stop"
152+
: "Unknown";
153+
return `EventActorIntent{actorId: "${actorId}", generation: ${generation}, intent: ${intentStr}}`;
154+
}
155+
case "EventActorStateUpdate": {
156+
const { actorId, generation, state } = event.val;
157+
let stateStr: string;
158+
if (state.tag === "ActorStateRunning") {
159+
stateStr = "Running";
160+
} else if (state.tag === "ActorStateStopped") {
161+
const { code, message } = state.val;
162+
const messageStr = message === null ? "null" : `"${message}"`;
163+
stateStr = `Stopped{code: ${code}, message: ${messageStr}}`;
164+
} else {
165+
stateStr = "Unknown";
166+
}
167+
return `EventActorStateUpdate{actorId: "${actorId}", generation: ${generation}, state: ${stateStr}}`;
168+
}
169+
case "EventActorSetAlarm": {
170+
const { actorId, generation, alarmTs } = event.val;
171+
const alarmTsStr =
172+
alarmTs === null ? "null" : stringifyBigInt(alarmTs);
173+
return `EventActorSetAlarm{actorId: "${actorId}", generation: ${generation}, alarmTs: ${alarmTsStr}}`;
174+
}
175+
}
176+
}
177+
178+
/**
179+
* Stringify EventWrapper for logging
180+
* Handles ArrayBuffers, BigInts, and Maps that can't be JSON.stringified
181+
*/
182+
export function stringifyEventWrapper(wrapper: protocol.EventWrapper): string {
183+
return `EventWrapper{index: ${stringifyBigInt(wrapper.index)}, inner: ${stringifyEvent(wrapper.inner)}}`;
184+
}

engine/sdks/typescript/runner/src/tunnel.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import type { Logger } from "pino";
44
import { stringify as uuidstringify, v4 as uuidv4 } from "uuid";
55
import { logger } from "./log";
66
import type { ActorInstance, Runner } from "./mod";
7+
import {
8+
stringifyToClientTunnelMessageKind,
9+
stringifyToServerTunnelMessageKind,
10+
} from "./stringify";
711
import { unreachable } from "./utils";
812
import { WebSocketTunnelAdapter } from "./websocket-tunnel-adapter";
913

@@ -90,9 +94,11 @@ export class Tunnel {
9094
) {
9195
// TODO: Switch this with runner WS
9296
if (!this.#runner.__webSocketReady()) {
93-
this.log?.warn(
94-
"cannot send tunnel message, socket not connected to engine",
95-
);
97+
this.log?.warn({
98+
msg: "cannot send tunnel message, socket not connected to engine",
99+
requestId: idToStr(requestId),
100+
message: stringifyToServerTunnelMessageKind(messageKind),
101+
});
96102
return;
97103
}
98104

@@ -110,7 +116,7 @@ export class Tunnel {
110116
msg: "send tunnel msg",
111117
requestId: requestIdStr,
112118
messageId: messageIdStr,
113-
message: messageKind,
119+
message: stringifyToServerTunnelMessageKind(messageKind),
114120
});
115121

116122
// Send message
@@ -283,7 +289,7 @@ export class Tunnel {
283289
msg: "receive tunnel msg",
284290
requestId: requestIdStr,
285291
messageId: messageIdStr,
286-
message: message.messageKind,
292+
message: stringifyToClientTunnelMessageKind(message.messageKind),
287293
});
288294

289295
if (message.messageKind.tag === "TunnelAck") {

0 commit comments

Comments
 (0)