rivetkit 2.3.18-rc.4 → 2.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/client.d.ts +723 -616
- package/dist/browser/client.js +184 -28
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/inspector/client.js +3 -1
- package/dist/browser/inspector/client.js.map +1 -1
- package/dist/tsup/actor/errors.cjs +6 -2
- package/dist/tsup/actor/errors.cjs.map +1 -1
- package/dist/tsup/actor/errors.d.cts +1 -1
- package/dist/tsup/actor/errors.d.ts +1 -1
- package/dist/tsup/actor/errors.js +5 -1
- package/dist/tsup/agent-os/index.cjs +3 -1
- package/dist/tsup/agent-os/index.cjs.map +1 -1
- package/dist/tsup/agent-os/index.d.cts +110 -3
- package/dist/tsup/agent-os/index.d.ts +110 -3
- package/dist/tsup/agent-os/index.js +3 -1
- package/dist/tsup/agent-os/index.js.map +1 -1
- package/dist/tsup/{chunk-ENDOWQTM.js → chunk-464WE4RF.js} +2 -2
- package/dist/tsup/{chunk-KKG2CTSI.js → chunk-4SC2NSAV.js} +2 -2
- package/dist/tsup/{chunk-R2WRP6VV.cjs → chunk-7A5EIXJJ.cjs} +7 -7
- package/dist/tsup/{chunk-R2WRP6VV.cjs.map → chunk-7A5EIXJJ.cjs.map} +1 -1
- package/dist/tsup/{chunk-GUVDWB2O.cjs → chunk-7BRRGBRY.cjs} +10 -10
- package/dist/tsup/{chunk-GUVDWB2O.cjs.map → chunk-7BRRGBRY.cjs.map} +1 -1
- package/dist/tsup/{chunk-KVPU65TI.js → chunk-7HTST3NX.js} +3 -3
- package/dist/tsup/{chunk-MS6C3B2I.js → chunk-BKX7UDTA.js} +185 -28
- package/dist/tsup/chunk-BKX7UDTA.js.map +1 -0
- package/dist/tsup/{chunk-FL2FDUSZ.js → chunk-DK3L22R6.js} +4 -4
- package/dist/tsup/{chunk-CAL23WOC.js → chunk-DN6MD3KK.js} +7 -7
- package/dist/tsup/chunk-DN6MD3KK.js.map +1 -0
- package/dist/tsup/{chunk-6W5VGLFT.js → chunk-EB77NZL4.js} +1 -1
- package/dist/tsup/chunk-EB77NZL4.js.map +1 -0
- package/dist/tsup/{chunk-4KGXFC6M.cjs → chunk-EO5UOXXY.cjs} +1 -1
- package/dist/tsup/chunk-EO5UOXXY.cjs.map +1 -0
- package/dist/tsup/{chunk-QFLG6UB4.cjs → chunk-G4U5L6AX.cjs} +3 -3
- package/dist/tsup/{chunk-QFLG6UB4.cjs.map → chunk-G4U5L6AX.cjs.map} +1 -1
- package/dist/tsup/{chunk-TGGF6SZN.cjs → chunk-IJUXBWH4.cjs} +351 -194
- package/dist/tsup/chunk-IJUXBWH4.cjs.map +1 -0
- package/dist/tsup/{chunk-2JSYYH6P.cjs → chunk-JX2ITWAV.cjs} +13 -2
- package/dist/tsup/chunk-JX2ITWAV.cjs.map +1 -0
- package/dist/tsup/{chunk-N3DJTMSZ.cjs → chunk-OGPFN6BT.cjs} +3 -3
- package/dist/tsup/{chunk-N3DJTMSZ.cjs.map → chunk-OGPFN6BT.cjs.map} +1 -1
- package/dist/tsup/{chunk-OUQUIBVW.js → chunk-P2OFXH4G.js} +12 -1
- package/dist/tsup/chunk-P2OFXH4G.js.map +1 -0
- package/dist/tsup/{chunk-F3IP3SGO.cjs → chunk-PPEIPCW4.cjs} +4 -4
- package/dist/tsup/{chunk-F3IP3SGO.cjs.map → chunk-PPEIPCW4.cjs.map} +1 -1
- package/dist/tsup/{chunk-7E2W2YSM.cjs → chunk-RJC5O2SD.cjs} +13 -13
- package/dist/tsup/chunk-RJC5O2SD.cjs.map +1 -0
- package/dist/tsup/{chunk-YQD6RRVP.js → chunk-WME6KOXW.js} +2 -2
- package/dist/tsup/{chunk-PLAJJOTE.js → chunk-X7RMJQGY.js} +2 -2
- package/dist/tsup/{chunk-4OMHYVOQ.cjs → chunk-Z4RAXFSD.cjs} +3 -3
- package/dist/tsup/{chunk-4OMHYVOQ.cjs.map → chunk-Z4RAXFSD.cjs.map} +1 -1
- package/dist/tsup/client/mod.cjs +6 -6
- package/dist/tsup/client/mod.d.cts +5 -5
- package/dist/tsup/client/mod.d.ts +5 -5
- package/dist/tsup/client/mod.js +5 -5
- package/dist/tsup/common/log.cjs +3 -3
- package/dist/tsup/common/log.js +2 -2
- package/dist/tsup/common/websocket.cjs +4 -4
- package/dist/tsup/common/websocket.js +3 -3
- package/dist/tsup/{config-gvHwMas-.d.cts → config-8n2AOhXK.d.cts} +114 -10
- package/dist/tsup/{config-Ug5M2MOr.d.ts → config-DEm0yIVV.d.ts} +114 -10
- package/dist/tsup/{context-DererUCI.d.ts → context-DGg2-IOm.d.ts} +1 -1
- package/dist/tsup/{context-BSCBvbfM.d.cts → context-DwjOVvlE.d.cts} +1 -1
- package/dist/tsup/db/drizzle.cjs +3 -3
- package/dist/tsup/db/drizzle.js +2 -2
- package/dist/tsup/db/mod.cjs +4 -4
- package/dist/tsup/db/mod.js +3 -3
- package/dist/tsup/dynamic/mod.cjs +2 -2
- package/dist/tsup/dynamic/mod.d.cts +3 -3
- package/dist/tsup/dynamic/mod.d.ts +3 -3
- package/dist/tsup/dynamic/mod.js +1 -1
- package/dist/tsup/inspector/mod.cjs +6 -6
- package/dist/tsup/inspector/mod.js +5 -5
- package/dist/tsup/inspector/workflow.cjs +5 -5
- package/dist/tsup/inspector/workflow.js +4 -4
- package/dist/tsup/inspector-tab/mod.cjs +2 -2
- package/dist/tsup/inspector-tab/mod.d.cts +4 -4
- package/dist/tsup/inspector-tab/mod.d.ts +4 -4
- package/dist/tsup/inspector-tab/mod.js +1 -1
- package/dist/tsup/mod.cjs +492 -319
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +5 -5
- package/dist/tsup/mod.d.ts +5 -5
- package/dist/tsup/mod.js +367 -194
- package/dist/tsup/mod.js.map +1 -1
- package/dist/tsup/test/mod.cjs +7 -7
- package/dist/tsup/test/mod.d.cts +3 -3
- package/dist/tsup/test/mod.d.ts +3 -3
- package/dist/tsup/test/mod.js +5 -5
- package/dist/tsup/{utils-Bbz-3411.d.cts → utils-CNFeS-Dk.d.cts} +1 -1
- package/dist/tsup/{utils-vvJQyygr.d.ts → utils-DsoDinPz.d.cts} +9 -1
- package/dist/tsup/{utils-vvJQyygr.d.cts → utils-DsoDinPz.d.ts} +9 -1
- package/dist/tsup/{utils-BqdWVlzm.d.ts → utils-OQHBjfcM.d.ts} +1 -1
- package/dist/tsup/utils.cjs +3 -3
- package/dist/tsup/utils.d.cts +2 -2
- package/dist/tsup/utils.d.ts +2 -2
- package/dist/tsup/utils.js +2 -2
- package/dist/tsup/workflow/mod.cjs +33 -27
- package/dist/tsup/workflow/mod.cjs.map +1 -1
- package/dist/tsup/workflow/mod.d.cts +5 -5
- package/dist/tsup/workflow/mod.d.ts +5 -5
- package/dist/tsup/workflow/mod.js +25 -19
- package/dist/tsup/workflow/mod.js.map +1 -1
- package/package.json +10 -8
- package/src/actor/config.ts +38 -0
- package/src/actor/errors.ts +31 -0
- package/src/client/actor-conn.ts +7 -0
- package/src/client/actor-handle.ts +57 -17
- package/src/client/client.ts +26 -6
- package/src/client/outbound-telemetry.ts +66 -0
- package/src/client/queue.ts +3 -0
- package/src/client/raw-utils.ts +3 -0
- package/src/common/actor-router-consts.ts +3 -0
- package/src/common/actor-telemetry-context.ts +19 -0
- package/src/common/otel-context.ts +99 -0
- package/src/common/utils.ts +1 -19
- package/src/engine-client/actor-http-client.ts +15 -0
- package/src/registry/index.ts +6 -0
- package/src/registry/napi-runtime.ts +155 -35
- package/src/registry/native.ts +277 -191
- package/src/registry/runtime.ts +66 -0
- package/src/registry/wasm-runtime.ts +40 -0
- package/src/workflow/driver.ts +20 -12
- package/dist/tsup/chunk-2JSYYH6P.cjs.map +0 -1
- package/dist/tsup/chunk-4KGXFC6M.cjs.map +0 -1
- package/dist/tsup/chunk-6W5VGLFT.js.map +0 -1
- package/dist/tsup/chunk-7E2W2YSM.cjs.map +0 -1
- package/dist/tsup/chunk-CAL23WOC.js.map +0 -1
- package/dist/tsup/chunk-MS6C3B2I.js.map +0 -1
- package/dist/tsup/chunk-OUQUIBVW.js.map +0 -1
- package/dist/tsup/chunk-TGGF6SZN.cjs.map +0 -1
- /package/dist/tsup/{chunk-ENDOWQTM.js.map → chunk-464WE4RF.js.map} +0 -0
- /package/dist/tsup/{chunk-KKG2CTSI.js.map → chunk-4SC2NSAV.js.map} +0 -0
- /package/dist/tsup/{chunk-KVPU65TI.js.map → chunk-7HTST3NX.js.map} +0 -0
- /package/dist/tsup/{chunk-FL2FDUSZ.js.map → chunk-DK3L22R6.js.map} +0 -0
- /package/dist/tsup/{chunk-YQD6RRVP.js.map → chunk-WME6KOXW.js.map} +0 -0
- /package/dist/tsup/{chunk-PLAJJOTE.js.map → chunk-X7RMJQGY.js.map} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AnyActorDefinition } from "@/actor/definition";
|
|
2
|
-
import type
|
|
2
|
+
import { type ActorSpecifier, encodeErrorForBridge } from "@/actor/errors";
|
|
3
|
+
import type { ActorInvocationSpanContext } from "@/common/actor-telemetry-context";
|
|
3
4
|
import {
|
|
4
5
|
HEADER_CONN_PARAMS,
|
|
5
6
|
HEADER_ENCODING,
|
|
@@ -24,6 +25,7 @@ import { AsyncMutex } from "@/common/database/shared";
|
|
|
24
25
|
import type { Encoding, JsonCompatValue } from "@/common/encoding";
|
|
25
26
|
import { deconstructError } from "@/common/utils";
|
|
26
27
|
import type { EngineControlClient } from "@/engine-client/driver";
|
|
28
|
+
import type { StartCallSpan, CurrentActorInvocation } from "@/registry/runtime";
|
|
27
29
|
import {
|
|
28
30
|
decodeCborCompat,
|
|
29
31
|
deserializeWithEncoding,
|
|
@@ -53,6 +55,7 @@ import { type ClientRaw, CREATE_ACTOR_CONN_PROXY } from "./client";
|
|
|
53
55
|
import { ActorError, isSchedulingError } from "./errors";
|
|
54
56
|
import { retryOnLifecycleBoundary } from "./lifecycle-errors";
|
|
55
57
|
import { logger } from "./log";
|
|
58
|
+
import { outboundTelemetryHeaders } from "./outbound-telemetry";
|
|
56
59
|
import {
|
|
57
60
|
createQueueSender,
|
|
58
61
|
type QueueSendNoWaitOptions,
|
|
@@ -82,6 +85,8 @@ export class ActorHandleRaw {
|
|
|
82
85
|
#resolvedActorId?: string;
|
|
83
86
|
#resolvingActorId?: Promise<string>;
|
|
84
87
|
#queueSendMutex = new AsyncMutex();
|
|
88
|
+
#currentActorInvocation?: CurrentActorInvocation;
|
|
89
|
+
#startCallSpan?: StartCallSpan;
|
|
85
90
|
|
|
86
91
|
/**
|
|
87
92
|
* Do not call this directly.
|
|
@@ -99,6 +104,8 @@ export class ActorHandleRaw {
|
|
|
99
104
|
actorResolutionState: ActorResolutionState,
|
|
100
105
|
gatewayOptions: ActorGatewayOptions = {},
|
|
101
106
|
signal?: AbortSignal,
|
|
107
|
+
currentActorInvocation?: CurrentActorInvocation,
|
|
108
|
+
startCallSpan?: StartCallSpan,
|
|
102
109
|
) {
|
|
103
110
|
this.#client = client;
|
|
104
111
|
this.#driver = driver;
|
|
@@ -108,6 +115,8 @@ export class ActorHandleRaw {
|
|
|
108
115
|
this.#params = params;
|
|
109
116
|
this.#getParams = getParams;
|
|
110
117
|
this.#signal = signal;
|
|
118
|
+
this.#currentActorInvocation = currentActorInvocation;
|
|
119
|
+
this.#startCallSpan = startCallSpan;
|
|
111
120
|
}
|
|
112
121
|
|
|
113
122
|
async #resolveConnectionParams(): Promise<unknown> {
|
|
@@ -166,6 +175,10 @@ export class ActorHandleRaw {
|
|
|
166
175
|
return await createQueueSender({
|
|
167
176
|
encoding: this.#encoding,
|
|
168
177
|
params: this.#params,
|
|
178
|
+
telemetryHeaders: () =>
|
|
179
|
+
outboundTelemetryHeaders(
|
|
180
|
+
this.#currentActorInvocation?.(),
|
|
181
|
+
),
|
|
169
182
|
customFetch: async (request: Request) => {
|
|
170
183
|
return await this.#driver.sendRequest(
|
|
171
184
|
target,
|
|
@@ -275,20 +288,41 @@ export class ActorHandleRaw {
|
|
|
275
288
|
// when no per-call signal is provided.
|
|
276
289
|
const signal = opts.signal ?? this.#signal;
|
|
277
290
|
const optsWithSignal = { ...opts, signal };
|
|
291
|
+
// Open before retries so all attempts share one span and parent context.
|
|
292
|
+
const call = this.#startCallSpan?.(
|
|
293
|
+
getActorNameFromQuery(this.#actorResolutionState),
|
|
294
|
+
opts.name,
|
|
295
|
+
);
|
|
278
296
|
const run = async () =>
|
|
279
|
-
(await this.#
|
|
280
|
-
|
|
281
|
-
|
|
297
|
+
(await this.#sendActionAttempts(
|
|
298
|
+
optsWithSignal,
|
|
299
|
+
call?.span,
|
|
300
|
+
)) as Response;
|
|
301
|
+
const send = async () => {
|
|
302
|
+
if (opts.name === "destroy") {
|
|
303
|
+
return await run();
|
|
304
|
+
}
|
|
305
|
+
return await retryOnLifecycleBoundary(run, { signal });
|
|
306
|
+
};
|
|
307
|
+
if (!call) {
|
|
308
|
+
return await send();
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const output = await send();
|
|
312
|
+
call.finish();
|
|
313
|
+
return output;
|
|
314
|
+
} catch (error) {
|
|
315
|
+
call.finish(encodeErrorForBridge(error));
|
|
316
|
+
throw error;
|
|
282
317
|
}
|
|
283
|
-
|
|
284
|
-
return await retryOnLifecycleBoundary(run, { signal });
|
|
285
318
|
}
|
|
286
319
|
|
|
287
|
-
async #
|
|
320
|
+
async #sendActionAttempts(
|
|
288
321
|
opts: {
|
|
289
322
|
name: string;
|
|
290
323
|
args: unknown[];
|
|
291
324
|
} & ActorActionOptions,
|
|
325
|
+
callSpan?: ActorInvocationSpanContext,
|
|
292
326
|
): Promise<unknown> {
|
|
293
327
|
const maxAttempts = this.#getDynamicQueryMaxAttempts();
|
|
294
328
|
let useQueryTarget = isDynamicActorQuery(this.#actorResolutionState);
|
|
@@ -320,6 +354,16 @@ export class ActorHandleRaw {
|
|
|
320
354
|
name: opts.name,
|
|
321
355
|
encoding: this.#encoding,
|
|
322
356
|
});
|
|
357
|
+
const headers: Record<string, string> = {
|
|
358
|
+
[HEADER_ENCODING]: this.#encoding,
|
|
359
|
+
...outboundTelemetryHeaders(
|
|
360
|
+
this.#currentActorInvocation?.(),
|
|
361
|
+
callSpan,
|
|
362
|
+
),
|
|
363
|
+
};
|
|
364
|
+
if (this.#params !== undefined) {
|
|
365
|
+
headers[HEADER_CONN_PARAMS] = JSON.stringify(this.#params);
|
|
366
|
+
}
|
|
323
367
|
const output = await sendHttpRequest<
|
|
324
368
|
protocol.HttpActionRequest,
|
|
325
369
|
protocol.HttpActionResponse,
|
|
@@ -330,16 +374,7 @@ export class ActorHandleRaw {
|
|
|
330
374
|
>({
|
|
331
375
|
url: `http://actor/action/${encodeURIComponent(opts.name)}`,
|
|
332
376
|
method: "POST",
|
|
333
|
-
headers
|
|
334
|
-
[HEADER_ENCODING]: this.#encoding,
|
|
335
|
-
...(this.#params !== undefined
|
|
336
|
-
? {
|
|
337
|
-
[HEADER_CONN_PARAMS]: JSON.stringify(
|
|
338
|
-
this.#params,
|
|
339
|
-
),
|
|
340
|
-
}
|
|
341
|
-
: {}),
|
|
342
|
-
},
|
|
377
|
+
headers,
|
|
343
378
|
body: opts.args,
|
|
344
379
|
encoding: this.#encoding,
|
|
345
380
|
customFetch: async (request) =>
|
|
@@ -643,6 +678,7 @@ export class ActorHandleRaw {
|
|
|
643
678
|
this.#encoding,
|
|
644
679
|
this.#actorResolutionState,
|
|
645
680
|
resolveActorGatewayOptions(this.#gatewayOptions, options),
|
|
681
|
+
this.#currentActorInvocation,
|
|
646
682
|
);
|
|
647
683
|
|
|
648
684
|
return this.#client[CREATE_ACTOR_CONN_PROXY](
|
|
@@ -680,6 +716,9 @@ export class ActorHandleRaw {
|
|
|
680
716
|
skipReadyWait,
|
|
681
717
|
},
|
|
682
718
|
);
|
|
719
|
+
const telemetryHeaders = outboundTelemetryHeaders(
|
|
720
|
+
this.#currentActorInvocation?.(),
|
|
721
|
+
);
|
|
683
722
|
|
|
684
723
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
685
724
|
let actorId: string | undefined;
|
|
@@ -698,6 +737,7 @@ export class ActorHandleRaw {
|
|
|
698
737
|
clonesInputBody ? input.clone() : input,
|
|
699
738
|
requestInit,
|
|
700
739
|
gatewayOptions,
|
|
740
|
+
telemetryHeaders,
|
|
701
741
|
);
|
|
702
742
|
const retry = await this.#shouldRetryRawFetchResponse(
|
|
703
743
|
response,
|
package/src/client/client.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { ActorQuery } from "@/client/query";
|
|
|
3
3
|
import type { Encoding } from "@/common/encoding";
|
|
4
4
|
import type { EngineControlClient } from "@/engine-client/driver";
|
|
5
5
|
import type { Registry } from "@/registry";
|
|
6
|
+
import type { StartCallSpan, CurrentActorInvocation } from "@/registry/runtime";
|
|
6
7
|
import type { ActorActionFunction, ActorGatewayOptions } from "./actor-common";
|
|
7
8
|
import {
|
|
8
9
|
type ActorConn,
|
|
@@ -175,6 +176,20 @@ export interface Region {
|
|
|
175
176
|
export const ACTOR_CONNS_SYMBOL = Symbol("actorConns");
|
|
176
177
|
export const CREATE_ACTOR_CONN_PROXY = Symbol("createActorConnProxy");
|
|
177
178
|
|
|
179
|
+
/** Options for constructing a raw actor client. */
|
|
180
|
+
export interface ClientRawOptions {
|
|
181
|
+
encoding?: Encoding;
|
|
182
|
+
gateway?: ActorGatewayOptions;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Runtime-supplied wiring for clients created inside an actor. Set only by the native runtime. */
|
|
186
|
+
export interface ActorClientRuntimeOptions {
|
|
187
|
+
/** Supplies the calling actor's invocation so actor-to-actor clients propagate its trace and ray ID. */
|
|
188
|
+
currentActorInvocation?: CurrentActorInvocation;
|
|
189
|
+
/** Opens and finishes the Core span covering an actor-to-actor call. */
|
|
190
|
+
startCallSpan?: StartCallSpan;
|
|
191
|
+
}
|
|
192
|
+
|
|
178
193
|
/**
|
|
179
194
|
* Client for managing & connecting to actors.
|
|
180
195
|
*
|
|
@@ -189,19 +204,22 @@ export class ClientRaw {
|
|
|
189
204
|
#driver: EngineControlClient;
|
|
190
205
|
#encodingKind: Encoding;
|
|
191
206
|
#gatewayOptions: ActorGatewayOptions;
|
|
207
|
+
#currentActorInvocation?: CurrentActorInvocation;
|
|
208
|
+
#startCallSpan?: StartCallSpan;
|
|
192
209
|
|
|
193
210
|
/**
|
|
194
211
|
* Creates an instance of Client.
|
|
195
212
|
*/
|
|
196
213
|
public constructor(
|
|
197
214
|
driver: EngineControlClient,
|
|
198
|
-
|
|
199
|
-
gatewayOptions: ActorGatewayOptions = {},
|
|
215
|
+
options: ClientRawOptions & ActorClientRuntimeOptions = {},
|
|
200
216
|
) {
|
|
201
217
|
this.#driver = driver;
|
|
202
218
|
|
|
203
|
-
this.#encodingKind = encoding ?? "bare";
|
|
204
|
-
this.#gatewayOptions =
|
|
219
|
+
this.#encodingKind = options.encoding ?? "bare";
|
|
220
|
+
this.#gatewayOptions = options.gateway ?? {};
|
|
221
|
+
this.#currentActorInvocation = options.currentActorInvocation;
|
|
222
|
+
this.#startCallSpan = options.startCallSpan;
|
|
205
223
|
}
|
|
206
224
|
|
|
207
225
|
/**
|
|
@@ -403,6 +421,8 @@ export class ClientRaw {
|
|
|
403
421
|
actorQuery,
|
|
404
422
|
this.#gatewayOptions,
|
|
405
423
|
signal,
|
|
424
|
+
this.#currentActorInvocation,
|
|
425
|
+
this.#startCallSpan,
|
|
406
426
|
);
|
|
407
427
|
}
|
|
408
428
|
|
|
@@ -459,9 +479,9 @@ export type AnyClient = Client<Registry<any>>;
|
|
|
459
479
|
|
|
460
480
|
export function createClientWithDriver<A extends Registry<any>>(
|
|
461
481
|
driver: EngineControlClient,
|
|
462
|
-
|
|
482
|
+
options: ClientRawOptions & ActorClientRuntimeOptions = {},
|
|
463
483
|
): Client<A> {
|
|
464
|
-
const client = new ClientRaw(driver,
|
|
484
|
+
const client = new ClientRaw(driver, options);
|
|
465
485
|
|
|
466
486
|
// Create proxy for accessing actors by name
|
|
467
487
|
return new Proxy(client, {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HEADER_RIVET_RAY_ID,
|
|
3
|
+
HEADER_TRACEPARENT,
|
|
4
|
+
HEADER_TRACESTATE,
|
|
5
|
+
} from "@/common/actor-router-consts";
|
|
6
|
+
import type { ActorInvocationTraceContext } from "@/common/actor-telemetry-context";
|
|
7
|
+
import {
|
|
8
|
+
actorInvocationTraceHeaders,
|
|
9
|
+
readActiveRayId,
|
|
10
|
+
readActiveTraceHeaders,
|
|
11
|
+
} from "@/common/otel-context";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Headers that carry a caller's ray ID and trace context into an actor. One
|
|
15
|
+
* rule for every kind of outbound call, so an action call and a queue send
|
|
16
|
+
* made from the same place land in the same trace under the same ray ID.
|
|
17
|
+
*
|
|
18
|
+
* The ray ID is the calling invocation's when the caller is itself inside an
|
|
19
|
+
* actor, else the one placed in OpenTelemetry baggage by the surrounding
|
|
20
|
+
* request handler. The trace context is `callSpan` when the runtime opened a
|
|
21
|
+
* span for this call, else the application span active in this JavaScript
|
|
22
|
+
* context, else the calling actor's own Core invocation span.
|
|
23
|
+
*/
|
|
24
|
+
export function outboundTelemetryHeaders(
|
|
25
|
+
invocation: ActorInvocationTraceContext | undefined,
|
|
26
|
+
callSpan?: ActorInvocationTraceContext["span"],
|
|
27
|
+
): Record<string, string> {
|
|
28
|
+
const headers: Record<string, string> = {};
|
|
29
|
+
const rayId = invocation?.rayId ?? readActiveRayId();
|
|
30
|
+
if (rayId) {
|
|
31
|
+
headers[HEADER_RIVET_RAY_ID] = rayId;
|
|
32
|
+
}
|
|
33
|
+
const traceHeaders =
|
|
34
|
+
actorInvocationTraceHeaders(callSpan) ??
|
|
35
|
+
readActiveTraceHeaders() ??
|
|
36
|
+
actorInvocationTraceHeaders(invocation?.span);
|
|
37
|
+
if (traceHeaders) {
|
|
38
|
+
headers[HEADER_TRACEPARENT] = traceHeaders.traceparent;
|
|
39
|
+
if (traceHeaders.tracestate) {
|
|
40
|
+
headers[HEADER_TRACESTATE] = traceHeaders.tracestate;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return headers;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Adds outbound telemetry headers to a request whose caller may have set
|
|
48
|
+
* some already. A header the caller set wins. `traceparent` and `tracestate`
|
|
49
|
+
* describe one span between them, so when the caller set either, both stay
|
|
50
|
+
* as the caller set them and neither is added.
|
|
51
|
+
*/
|
|
52
|
+
export function addOutboundTelemetryHeaders(
|
|
53
|
+
headers: Headers,
|
|
54
|
+
telemetry: Record<string, string>,
|
|
55
|
+
): void {
|
|
56
|
+
const callerSetTraceContext =
|
|
57
|
+
headers.has(HEADER_TRACEPARENT) || headers.has(HEADER_TRACESTATE);
|
|
58
|
+
for (const [name, value] of Object.entries(telemetry)) {
|
|
59
|
+
const isTraceContext =
|
|
60
|
+
name === HEADER_TRACEPARENT || name === HEADER_TRACESTATE;
|
|
61
|
+
if (isTraceContext ? callerSetTraceContext : headers.has(name)) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
headers.set(name, value);
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/client/queue.ts
CHANGED
|
@@ -54,6 +54,8 @@ export interface QueueSendResult<TResponse = unknown> {
|
|
|
54
54
|
interface QueueSenderOptions {
|
|
55
55
|
encoding: Encoding;
|
|
56
56
|
params: unknown;
|
|
57
|
+
/** Ray ID and trace context headers, read per send. */
|
|
58
|
+
telemetryHeaders: () => Record<string, string>;
|
|
57
59
|
customFetch: (request: Request) => Promise<Response>;
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -90,6 +92,7 @@ export function createQueueSender(
|
|
|
90
92
|
method: "POST",
|
|
91
93
|
headers: {
|
|
92
94
|
[HEADER_ENCODING]: senderOptions.encoding,
|
|
95
|
+
...senderOptions.telemetryHeaders(),
|
|
93
96
|
...(senderOptions.params !== undefined
|
|
94
97
|
? {
|
|
95
98
|
[HEADER_CONN_PARAMS]: JSON.stringify(
|
package/src/client/raw-utils.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
} from "@/engine-client/driver";
|
|
13
13
|
import { ActorError } from "./errors";
|
|
14
14
|
import { logger } from "./log";
|
|
15
|
+
import { addOutboundTelemetryHeaders } from "./outbound-telemetry";
|
|
15
16
|
|
|
16
17
|
/** Buffer a one-shot ReadableStream body to bytes so every retry attempt can re-send it. */
|
|
17
18
|
export async function prepareRetryableInit(
|
|
@@ -37,6 +38,7 @@ export async function rawHttpFetch(
|
|
|
37
38
|
input: string | URL | Request,
|
|
38
39
|
init?: RequestInit,
|
|
39
40
|
options: GatewayRequestOptions = {},
|
|
41
|
+
telemetryHeaders: Record<string, string> = {},
|
|
40
42
|
): Promise<Response> {
|
|
41
43
|
// Extract path and merge init options
|
|
42
44
|
let path: string;
|
|
@@ -111,6 +113,7 @@ export async function rawHttpFetch(
|
|
|
111
113
|
if (params) {
|
|
112
114
|
proxyRequestHeaders.set(HEADER_CONN_PARAMS, JSON.stringify(params));
|
|
113
115
|
}
|
|
116
|
+
addOutboundTelemetryHeaders(proxyRequestHeaders, telemetryHeaders);
|
|
114
117
|
|
|
115
118
|
// Forward the request to the actor
|
|
116
119
|
const proxyRequest = new Request(url, {
|
|
@@ -20,6 +20,9 @@ export const HEADER_ACTOR_GENERATION = "x-rivet-actor-generation";
|
|
|
20
20
|
export const HEADER_ACTOR_KEY = "x-rivet-actor-key";
|
|
21
21
|
|
|
22
22
|
export const HEADER_RIVET_TOKEN = "x-rivet-token";
|
|
23
|
+
export const HEADER_RIVET_RAY_ID = "x-rivet-ray-id";
|
|
24
|
+
export const HEADER_TRACEPARENT = "traceparent";
|
|
25
|
+
export const HEADER_TRACESTATE = "tracestate";
|
|
23
26
|
|
|
24
27
|
// MARK: Manager Gateway Headers
|
|
25
28
|
export const HEADER_RIVET_TARGET = "x-rivet-target";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Correlation owned by the currently executing Core actor invocation. */
|
|
2
|
+
export interface ActorInvocationTraceContext {
|
|
3
|
+
/** Ray ID the invocation received, absent when nothing upstream supplied one. */
|
|
4
|
+
readonly rayId?: string;
|
|
5
|
+
/** Core-owned invocation span context, absent when tracing is disabled. */
|
|
6
|
+
readonly span?: ActorInvocationSpanContext;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** W3C span context of the Core invocation span. */
|
|
10
|
+
export interface ActorInvocationSpanContext {
|
|
11
|
+
/** W3C trace identifier. */
|
|
12
|
+
readonly traceId: string;
|
|
13
|
+
/** W3C span identifier for the Core invocation. */
|
|
14
|
+
readonly spanId: string;
|
|
15
|
+
/** OpenTelemetry trace flags encoded as an integer. */
|
|
16
|
+
readonly traceFlags: number;
|
|
17
|
+
/** Optional vendor trace state inherited by the Core invocation. */
|
|
18
|
+
readonly tracestate?: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Context,
|
|
3
|
+
context,
|
|
4
|
+
createTraceState,
|
|
5
|
+
isSpanContextValid,
|
|
6
|
+
propagation,
|
|
7
|
+
type SpanContext,
|
|
8
|
+
trace,
|
|
9
|
+
} from "@opentelemetry/api";
|
|
10
|
+
import type { ActorInvocationSpanContext } from "./actor-telemetry-context";
|
|
11
|
+
|
|
12
|
+
/** W3C headers derived from the active JavaScript OTel context. */
|
|
13
|
+
export interface ActiveTraceHeaders {
|
|
14
|
+
/** W3C Trace Context identifying the active trace and span. */
|
|
15
|
+
readonly traceparent: string;
|
|
16
|
+
/** Optional vendor trace state associated with the active span. */
|
|
17
|
+
readonly tracestate?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Returns the active W3C trace context, when an OTel provider has installed one. */
|
|
21
|
+
export function readActiveTraceHeaders(): ActiveTraceHeaders | undefined {
|
|
22
|
+
return traceHeaders(trace.getSpanContext(context.active()));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** W3C Baggage key that carries a ray ID through application code. */
|
|
26
|
+
export const RAY_BAGGAGE_KEY = "rivet.ray.id";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns the ray ID carried in the active OpenTelemetry baggage, so a request
|
|
30
|
+
* handler that received a ray ID can pass it to the actors it calls. The bound
|
|
31
|
+
* is the one Core applies on receipt, so an invalid value is never sent.
|
|
32
|
+
*/
|
|
33
|
+
export function readActiveRayId(): string | undefined {
|
|
34
|
+
const value = propagation
|
|
35
|
+
.getBaggage(context.active())
|
|
36
|
+
?.getEntry(RAY_BAGGAGE_KEY)?.value;
|
|
37
|
+
if (value && value.length <= 30 && /^[A-Za-z0-9_-]+$/.test(value)) {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** W3C headers for the Core invocation span, or nothing when it is absent or invalid. */
|
|
44
|
+
export function actorInvocationTraceHeaders(
|
|
45
|
+
invocation: ActorInvocationSpanContext | undefined,
|
|
46
|
+
): ActiveTraceHeaders | undefined {
|
|
47
|
+
const spanContext = invocationSpanContext(invocation);
|
|
48
|
+
if (!spanContext) return undefined;
|
|
49
|
+
return traceHeaders(spanContext);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function traceHeaders(
|
|
53
|
+
spanContext: SpanContext | undefined,
|
|
54
|
+
): ActiveTraceHeaders | undefined {
|
|
55
|
+
if (!spanContext || !isSpanContextValid(spanContext)) return undefined;
|
|
56
|
+
const tracestate = spanContext.traceState?.serialize();
|
|
57
|
+
return {
|
|
58
|
+
traceparent: `00-${spanContext.traceId}-${spanContext.spanId}-${spanContext.traceFlags.toString(16).padStart(2, "0")}`,
|
|
59
|
+
...(tracestate ? { tracestate } : {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Runs `run` with the Core invocation span as the active OpenTelemetry span,
|
|
65
|
+
* so application spans started inside an actor callback nest under it. With
|
|
66
|
+
* no span, or an invalid one, `run` executes unchanged.
|
|
67
|
+
*/
|
|
68
|
+
export function runWithActorInvocationSpan<T>(
|
|
69
|
+
invocation: ActorInvocationSpanContext | undefined,
|
|
70
|
+
run: () => T,
|
|
71
|
+
): T {
|
|
72
|
+
if (!invocation) return run();
|
|
73
|
+
|
|
74
|
+
const spanContext = invocationSpanContext(invocation);
|
|
75
|
+
if (!spanContext) return run();
|
|
76
|
+
const parent: Context = trace.setSpanContext(context.active(), spanContext);
|
|
77
|
+
|
|
78
|
+
return context.with(parent, run);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function invocationSpanContext(
|
|
82
|
+
invocation: ActorInvocationSpanContext | undefined,
|
|
83
|
+
): SpanContext | undefined {
|
|
84
|
+
if (!invocation) return undefined;
|
|
85
|
+
try {
|
|
86
|
+
const spanContext: SpanContext = {
|
|
87
|
+
traceId: invocation.traceId,
|
|
88
|
+
spanId: invocation.spanId,
|
|
89
|
+
traceFlags: invocation.traceFlags,
|
|
90
|
+
traceState: invocation.tracestate
|
|
91
|
+
? createTraceState(invocation.tracestate)
|
|
92
|
+
: undefined,
|
|
93
|
+
isRemote: false,
|
|
94
|
+
};
|
|
95
|
+
return isSpanContextValid(spanContext) ? spanContext : undefined;
|
|
96
|
+
} catch {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
package/src/common/utils.ts
CHANGED
|
@@ -48,24 +48,6 @@ export interface DeconstructedError {
|
|
|
48
48
|
actor?: errors.ActorSpecifier;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function isCanonicalStructuredRivetError(
|
|
52
|
-
error: unknown,
|
|
53
|
-
): error is errors.RivetErrorLike {
|
|
54
|
-
return (
|
|
55
|
-
error instanceof errors.RivetError ||
|
|
56
|
-
(typeof error === "object" &&
|
|
57
|
-
error !== null &&
|
|
58
|
-
"__type" in error &&
|
|
59
|
-
error.__type === "RivetError" &&
|
|
60
|
-
"group" in error &&
|
|
61
|
-
typeof error.group === "string" &&
|
|
62
|
-
"code" in error &&
|
|
63
|
-
typeof error.code === "string" &&
|
|
64
|
-
"message" in error &&
|
|
65
|
-
typeof error.message === "string")
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
51
|
/**
|
|
70
52
|
* Deconstructs errors into response fields. Bridge callback errors that cross
|
|
71
53
|
* into rivetkit-core are sanitized there; this only classifies JS-local errors.
|
|
@@ -85,7 +67,7 @@ export function deconstructError(
|
|
|
85
67
|
let actor: errors.ActorSpecifier | undefined;
|
|
86
68
|
// Structured errors from core or from pre-built `RivetError` instances are canonical.
|
|
87
69
|
// Only unstructured errors go through the classifier below.
|
|
88
|
-
if (isCanonicalStructuredRivetError(error)) {
|
|
70
|
+
if (errors.isCanonicalStructuredRivetError(error)) {
|
|
89
71
|
statusCode = (
|
|
90
72
|
typeof error.statusCode === "number"
|
|
91
73
|
? error.statusCode
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ClientConfig } from "@/client/config";
|
|
2
2
|
import {
|
|
3
3
|
HEADER_RIVET_ACTOR,
|
|
4
|
+
HEADER_RIVET_RAY_ID,
|
|
4
5
|
HEADER_RIVET_SKIP_READY_WAIT,
|
|
5
6
|
HEADER_RIVET_TARGET,
|
|
6
7
|
HEADER_RIVET_TOKEN,
|
|
8
|
+
HEADER_TRACEPARENT,
|
|
9
|
+
HEADER_TRACESTATE,
|
|
7
10
|
} from "@/common/actor-router-consts";
|
|
8
11
|
import { type GatewayRequestOptions, shouldSkipReadyWait } from "./driver";
|
|
9
12
|
|
|
@@ -55,6 +58,18 @@ function buildGuardHeaders(
|
|
|
55
58
|
for (const [key, value] of Object.entries(runConfig.headers)) {
|
|
56
59
|
headers.set(key, value as string);
|
|
57
60
|
}
|
|
61
|
+
// Configured trace context is never sent: it would pin every call to one span.
|
|
62
|
+
for (const name of [HEADER_TRACEPARENT, HEADER_TRACESTATE]) {
|
|
63
|
+
headers.delete(name);
|
|
64
|
+
const value = actorRequest.headers.get(name);
|
|
65
|
+
if (value !== null) {
|
|
66
|
+
headers.set(name, value);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const requestRayId = actorRequest.headers.get(HEADER_RIVET_RAY_ID);
|
|
70
|
+
if (requestRayId !== null) {
|
|
71
|
+
headers.set(HEADER_RIVET_RAY_ID, requestRayId);
|
|
72
|
+
}
|
|
58
73
|
// Add guard-specific headers
|
|
59
74
|
if (runConfig.token) {
|
|
60
75
|
headers.set(HEADER_RIVET_TOKEN, runConfig.token);
|
package/src/registry/index.ts
CHANGED
|
@@ -732,6 +732,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
732
732
|
async #drain(config: RegistryConfig): Promise<void> {
|
|
733
733
|
const modeAPromise = this.#runtimeServeConfiguredPromise;
|
|
734
734
|
const modeBPromise = this.#runtimeServerlessPromise;
|
|
735
|
+
const runtimes = new Set<CoreRuntime>();
|
|
735
736
|
|
|
736
737
|
const gracePeriodMs =
|
|
737
738
|
config.shutdown?.gracePeriodMs ??
|
|
@@ -751,6 +752,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
751
752
|
(async () => {
|
|
752
753
|
try {
|
|
753
754
|
const { runtime, registry } = await modeAPromise;
|
|
755
|
+
runtimes.add(runtime);
|
|
754
756
|
await runtime.shutdownRegistry(registry);
|
|
755
757
|
} catch (err) {
|
|
756
758
|
logger().warn(
|
|
@@ -766,6 +768,7 @@ export class Registry<A extends RegistryActors> {
|
|
|
766
768
|
(async () => {
|
|
767
769
|
try {
|
|
768
770
|
const { runtime, registry } = await modeBPromise;
|
|
771
|
+
runtimes.add(runtime);
|
|
769
772
|
await runtime.shutdownRegistry(registry);
|
|
770
773
|
} catch (err) {
|
|
771
774
|
logger().warn(
|
|
@@ -795,6 +798,9 @@ export class Registry<A extends RegistryActors> {
|
|
|
795
798
|
setTimeout(resolve, gracePeriodMs).unref?.(),
|
|
796
799
|
),
|
|
797
800
|
]);
|
|
801
|
+
await Promise.all(
|
|
802
|
+
[...runtimes].map((runtime) => runtime.shutdownTelemetry?.()),
|
|
803
|
+
);
|
|
798
804
|
}
|
|
799
805
|
|
|
800
806
|
async #actorStopThresholdMs(
|