@trigger.dev/sdk 4.3.0 → 4.3.1
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/commonjs/v3/batch.d.ts +3 -3
- package/dist/commonjs/v3/batch.js.map +1 -1
- package/dist/commonjs/v3/idempotencyKeys.d.ts +2 -1
- package/dist/commonjs/v3/idempotencyKeys.js +1 -0
- package/dist/commonjs/v3/idempotencyKeys.js.map +1 -1
- package/dist/commonjs/v3/shared.d.ts +71 -0
- package/dist/commonjs/v3/shared.js +880 -542
- package/dist/commonjs/v3/shared.js.map +1 -1
- package/dist/commonjs/v3/shared.test.d.ts +1 -0
- package/dist/commonjs/v3/shared.test.js +190 -0
- package/dist/commonjs/v3/shared.test.js.map +1 -0
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/v3/batch.d.ts +3 -3
- package/dist/esm/v3/batch.js +1 -1
- package/dist/esm/v3/batch.js.map +1 -1
- package/dist/esm/v3/idempotencyKeys.d.ts +2 -1
- package/dist/esm/v3/idempotencyKeys.js +2 -1
- package/dist/esm/v3/idempotencyKeys.js.map +1 -1
- package/dist/esm/v3/shared.d.ts +71 -0
- package/dist/esm/v3/shared.js +879 -541
- package/dist/esm/v3/shared.js.map +1 -1
- package/dist/esm/v3/shared.test.d.ts +1 -0
- package/dist/esm/v3/shared.test.js +188 -0
- package/dist/esm/v3/shared.test.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/package.json +3 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TaskRunPromise = exports.SubtaskUnwrapError = void 0;
|
|
3
|
+
exports.BatchTriggerError = exports.TaskRunPromise = exports.SubtaskUnwrapError = void 0;
|
|
4
4
|
exports.queue = queue;
|
|
5
5
|
exports.createTask = createTask;
|
|
6
6
|
exports.createToolTask = createToolTask;
|
|
@@ -13,6 +13,7 @@ exports.batchTriggerById = batchTriggerById;
|
|
|
13
13
|
exports.batchTriggerByIdAndWait = batchTriggerByIdAndWait;
|
|
14
14
|
exports.batchTriggerTasks = batchTriggerTasks;
|
|
15
15
|
exports.batchTriggerAndWaitTasks = batchTriggerAndWaitTasks;
|
|
16
|
+
exports.readableStreamToAsyncIterable = readableStreamToAsyncIterable;
|
|
16
17
|
const api_1 = require("@opentelemetry/api");
|
|
17
18
|
const v3_1 = require("@trigger.dev/core/v3");
|
|
18
19
|
Object.defineProperty(exports, "SubtaskUnwrapError", { enumerable: true, get: function () { return v3_1.SubtaskUnwrapError; } });
|
|
@@ -237,63 +238,14 @@ async function batchTriggerAndWait(id, items, options, requestOptions) {
|
|
|
237
238
|
async function batchTrigger(id, items, options, requestOptions) {
|
|
238
239
|
return await batchTrigger_internal("tasks.batchTrigger()", id, items, options, undefined, requestOptions);
|
|
239
240
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
* @template TTask - The type of task(s) to be triggered, extends AnyTask
|
|
244
|
-
*
|
|
245
|
-
* @param {Array<BatchByIdItem<InferRunTypes<TTask>>>} items - Array of task items to trigger
|
|
246
|
-
* @param {BatchTriggerOptions} [options] - Optional batch-level trigger options
|
|
247
|
-
* @param {TriggerApiRequestOptions} [requestOptions] - Optional API request configuration
|
|
248
|
-
*
|
|
249
|
-
* @returns {Promise<BatchRunHandleFromTypes<InferRunTypes<TTask>>>} A promise that resolves with the batch run handle
|
|
250
|
-
* containing batch ID, cached status, idempotency info, runs, and public access token
|
|
251
|
-
*
|
|
252
|
-
* @example
|
|
253
|
-
* ```ts
|
|
254
|
-
* import { batch } from "@trigger.dev/sdk/v3";
|
|
255
|
-
* import type { myTask1, myTask2 } from "~/trigger/myTasks";
|
|
256
|
-
*
|
|
257
|
-
* // Trigger multiple tasks with different payloads
|
|
258
|
-
* const result = await batch.trigger<typeof myTask1 | typeof myTask2>([
|
|
259
|
-
* {
|
|
260
|
-
* id: "my-task-1",
|
|
261
|
-
* payload: { some: "data" },
|
|
262
|
-
* options: {
|
|
263
|
-
* queue: "default",
|
|
264
|
-
* concurrencyKey: "key",
|
|
265
|
-
* idempotencyKey: "unique-key",
|
|
266
|
-
* delay: "5m",
|
|
267
|
-
* tags: ["tag1", "tag2"]
|
|
268
|
-
* }
|
|
269
|
-
* },
|
|
270
|
-
* {
|
|
271
|
-
* id: "my-task-2",
|
|
272
|
-
* payload: { other: "data" }
|
|
273
|
-
* }
|
|
274
|
-
* ]);
|
|
275
|
-
* ```
|
|
276
|
-
*
|
|
277
|
-
* @description
|
|
278
|
-
* Each task item in the array can include:
|
|
279
|
-
* - `id`: The unique identifier of the task
|
|
280
|
-
* - `payload`: The data to pass to the task
|
|
281
|
-
* - `options`: Optional task-specific settings including:
|
|
282
|
-
* - `queue`: Specify a queue for the task
|
|
283
|
-
* - `concurrencyKey`: Control concurrent execution
|
|
284
|
-
* - `idempotencyKey`: Prevent duplicate runs
|
|
285
|
-
* - `idempotencyKeyTTL`: Time-to-live for idempotency key
|
|
286
|
-
* - `delay`: Delay before task execution
|
|
287
|
-
* - `ttl`: Time-to-live for the task
|
|
288
|
-
* - `tags`: Array of tags for the task
|
|
289
|
-
* - `maxAttempts`: Maximum retry attempts
|
|
290
|
-
* - `metadata`: Additional metadata
|
|
291
|
-
* - `maxDuration`: Maximum execution duration
|
|
292
|
-
*/
|
|
293
|
-
async function batchTriggerById(items, options, requestOptions) {
|
|
241
|
+
// Implementation
|
|
242
|
+
async function batchTriggerById(...args) {
|
|
243
|
+
const [items, options, requestOptions] = args;
|
|
294
244
|
const apiClient = v3_1.apiClientManager.clientOrThrow(requestOptions?.clientConfig);
|
|
295
|
-
|
|
296
|
-
|
|
245
|
+
// Check if items is an array or a stream
|
|
246
|
+
if (Array.isArray(items)) {
|
|
247
|
+
// Array path: existing logic
|
|
248
|
+
const ndJsonItems = await Promise.all(items.map(async (item, index) => {
|
|
297
249
|
const taskMetadata = v3_1.resourceCatalog.getTask(item.id);
|
|
298
250
|
const parsedPayload = taskMetadata?.fns.parsePayload
|
|
299
251
|
? await taskMetadata?.fns.parsePayload(item.payload)
|
|
@@ -301,6 +253,7 @@ async function batchTriggerById(items, options, requestOptions) {
|
|
|
301
253
|
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
302
254
|
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
303
255
|
return {
|
|
256
|
+
index,
|
|
304
257
|
task: item.id,
|
|
305
258
|
payload: payloadPacket.data,
|
|
306
259
|
options: {
|
|
@@ -320,257 +273,266 @@ async function batchTriggerById(items, options, requestOptions) {
|
|
|
320
273
|
priority: item.options?.priority,
|
|
321
274
|
region: item.options?.region,
|
|
322
275
|
lockToVersion: item.options?.version ?? (0, v3_1.getEnvVar)("TRIGGER_VERSION"),
|
|
276
|
+
debounce: item.options?.debounce,
|
|
323
277
|
},
|
|
324
278
|
};
|
|
325
|
-
}))
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
279
|
+
}));
|
|
280
|
+
// Execute 2-phase batch
|
|
281
|
+
const response = await tracer_js_1.tracer.startActiveSpan("batch.trigger()", async (span) => {
|
|
282
|
+
const result = await executeBatchTwoPhase(apiClient, ndJsonItems, {
|
|
283
|
+
parentRunId: v3_1.taskContext.ctx?.run.id,
|
|
284
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
285
|
+
spanParentAsLink: true, // Fire-and-forget: child runs get separate trace IDs
|
|
286
|
+
}, requestOptions);
|
|
287
|
+
span.setAttribute("batchId", result.id);
|
|
288
|
+
span.setAttribute("runCount", result.runCount);
|
|
289
|
+
return result;
|
|
290
|
+
}, {
|
|
291
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
292
|
+
attributes: {
|
|
293
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
const handle = {
|
|
297
|
+
batchId: response.id,
|
|
298
|
+
runCount: response.runCount,
|
|
299
|
+
publicAccessToken: response.publicAccessToken,
|
|
300
|
+
};
|
|
301
|
+
return handle;
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
// Stream path: convert to AsyncIterable and transform
|
|
305
|
+
const asyncItems = normalizeToAsyncIterable(items);
|
|
306
|
+
const transformedItems = transformBatchItemsStream(asyncItems, options);
|
|
307
|
+
// Execute streaming 2-phase batch
|
|
308
|
+
const response = await tracer_js_1.tracer.startActiveSpan("batch.trigger()", async (span) => {
|
|
309
|
+
const result = await executeBatchTwoPhaseStreaming(apiClient, transformedItems, {
|
|
310
|
+
parentRunId: v3_1.taskContext.ctx?.run.id,
|
|
311
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
312
|
+
spanParentAsLink: true, // Fire-and-forget: child runs get separate trace IDs
|
|
313
|
+
}, requestOptions);
|
|
314
|
+
span.setAttribute("batchId", result.id);
|
|
315
|
+
span.setAttribute("runCount", result.runCount);
|
|
316
|
+
return result;
|
|
317
|
+
}, {
|
|
318
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
319
|
+
attributes: {
|
|
320
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
const handle = {
|
|
324
|
+
batchId: response.id,
|
|
325
|
+
runCount: response.runCount,
|
|
326
|
+
publicAccessToken: response.publicAccessToken,
|
|
327
|
+
};
|
|
328
|
+
return handle;
|
|
329
|
+
}
|
|
352
330
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
*
|
|
357
|
-
* @template TTask - Union type of tasks to be triggered, extends AnyTask
|
|
358
|
-
*
|
|
359
|
-
* @param {Array<BatchByIdAndWaitItem<InferRunTypes<TTask>>>} items - Array of task items to trigger
|
|
360
|
-
* @param {TriggerApiRequestOptions} [requestOptions] - Optional API request configuration
|
|
361
|
-
*
|
|
362
|
-
* @returns {Promise<BatchByIdResult<TTask>>} A promise that resolves with the batch results, including
|
|
363
|
-
* success/failure status and strongly-typed outputs for each task
|
|
364
|
-
*
|
|
365
|
-
* @throws {Error} If called outside of a task.run() context
|
|
366
|
-
* @throws {Error} If no API client is configured
|
|
367
|
-
*
|
|
368
|
-
* @example
|
|
369
|
-
* ```ts
|
|
370
|
-
* import { batch, task } from "@trigger.dev/sdk/v3";
|
|
371
|
-
*
|
|
372
|
-
* export const parentTask = task({
|
|
373
|
-
* id: "parent-task",
|
|
374
|
-
* run: async (payload: string) => {
|
|
375
|
-
* const results = await batch.triggerAndWait<typeof childTask1 | typeof childTask2>([
|
|
376
|
-
* {
|
|
377
|
-
* id: "child-task-1",
|
|
378
|
-
* payload: { foo: "World" },
|
|
379
|
-
* options: {
|
|
380
|
-
* queue: "default",
|
|
381
|
-
* delay: "5m",
|
|
382
|
-
* tags: ["batch", "child1"]
|
|
383
|
-
* }
|
|
384
|
-
* },
|
|
385
|
-
* {
|
|
386
|
-
* id: "child-task-2",
|
|
387
|
-
* payload: { bar: 42 }
|
|
388
|
-
* }
|
|
389
|
-
* ]);
|
|
390
|
-
*
|
|
391
|
-
* // Type-safe result handling
|
|
392
|
-
* for (const result of results) {
|
|
393
|
-
* if (result.ok) {
|
|
394
|
-
* switch (result.taskIdentifier) {
|
|
395
|
-
* case "child-task-1":
|
|
396
|
-
* console.log("Child task 1 output:", result.output); // string type
|
|
397
|
-
* break;
|
|
398
|
-
* case "child-task-2":
|
|
399
|
-
* console.log("Child task 2 output:", result.output); // number type
|
|
400
|
-
* break;
|
|
401
|
-
* }
|
|
402
|
-
* } else {
|
|
403
|
-
* console.error("Task failed:", result.error);
|
|
404
|
-
* }
|
|
405
|
-
* }
|
|
406
|
-
* }
|
|
407
|
-
* });
|
|
408
|
-
* ```
|
|
409
|
-
*
|
|
410
|
-
* @description
|
|
411
|
-
* Each task item in the array can include:
|
|
412
|
-
* - `id`: The task identifier (must match one of the tasks in the union type)
|
|
413
|
-
* - `payload`: Strongly-typed payload matching the task's input type
|
|
414
|
-
* - `options`: Optional task-specific settings including:
|
|
415
|
-
* - `queue`: Specify a queue for the task
|
|
416
|
-
* - `concurrencyKey`: Control concurrent execution
|
|
417
|
-
* - `delay`: Delay before task execution
|
|
418
|
-
* - `ttl`: Time-to-live for the task
|
|
419
|
-
* - `tags`: Array of tags for the task
|
|
420
|
-
* - `maxAttempts`: Maximum retry attempts
|
|
421
|
-
* - `metadata`: Additional metadata
|
|
422
|
-
* - `maxDuration`: Maximum execution duration
|
|
423
|
-
*
|
|
424
|
-
* The function provides full type safety for:
|
|
425
|
-
* - Task IDs
|
|
426
|
-
* - Payload types
|
|
427
|
-
* - Return value types
|
|
428
|
-
* - Error handling
|
|
429
|
-
*/
|
|
430
|
-
async function batchTriggerByIdAndWait(items, options, requestOptions) {
|
|
331
|
+
// Implementation
|
|
332
|
+
async function batchTriggerByIdAndWait(...args) {
|
|
333
|
+
const [items, options, requestOptions] = args;
|
|
431
334
|
const ctx = v3_1.taskContext.ctx;
|
|
432
335
|
if (!ctx) {
|
|
433
336
|
throw new Error("batchTriggerAndWait can only be used from inside a task.run()");
|
|
434
337
|
}
|
|
435
338
|
const apiClient = v3_1.apiClientManager.clientOrThrow(requestOptions?.clientConfig);
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
339
|
+
// Check if items is an array or a stream
|
|
340
|
+
if (Array.isArray(items)) {
|
|
341
|
+
// Array path: existing logic
|
|
342
|
+
const ndJsonItems = await Promise.all(items.map(async (item, index) => {
|
|
343
|
+
const taskMetadata = v3_1.resourceCatalog.getTask(item.id);
|
|
344
|
+
const parsedPayload = taskMetadata?.fns.parsePayload
|
|
345
|
+
? await taskMetadata?.fns.parsePayload(item.payload)
|
|
346
|
+
: item.payload;
|
|
347
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
348
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
349
|
+
return {
|
|
350
|
+
index,
|
|
351
|
+
task: item.id,
|
|
352
|
+
payload: payloadPacket.data,
|
|
353
|
+
options: {
|
|
354
|
+
lockToVersion: v3_1.taskContext.worker?.version,
|
|
355
|
+
queue: item.options?.queue ? { name: item.options.queue } : undefined,
|
|
356
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
357
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
358
|
+
payloadType: payloadPacket.dataType,
|
|
359
|
+
delay: item.options?.delay,
|
|
360
|
+
ttl: item.options?.ttl,
|
|
361
|
+
tags: item.options?.tags,
|
|
362
|
+
maxAttempts: item.options?.maxAttempts,
|
|
363
|
+
metadata: item.options?.metadata,
|
|
364
|
+
maxDuration: item.options?.maxDuration,
|
|
365
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
366
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
367
|
+
machine: item.options?.machine,
|
|
368
|
+
priority: item.options?.priority,
|
|
369
|
+
region: item.options?.region,
|
|
370
|
+
debounce: item.options?.debounce,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}));
|
|
374
|
+
return await tracer_js_1.tracer.startActiveSpan("batch.triggerAndWait()", async (span) => {
|
|
375
|
+
// Execute 2-phase batch
|
|
376
|
+
const response = await executeBatchTwoPhase(apiClient, ndJsonItems, {
|
|
377
|
+
parentRunId: ctx.run.id,
|
|
378
|
+
resumeParentOnCompletion: true,
|
|
379
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
380
|
+
spanParentAsLink: false, // Waiting: child runs share parent's trace ID
|
|
381
|
+
}, requestOptions);
|
|
382
|
+
span.setAttribute("batchId", response.id);
|
|
383
|
+
span.setAttribute("runCount", response.runCount);
|
|
384
|
+
const result = await v3_1.runtime.waitForBatch({
|
|
385
|
+
id: response.id,
|
|
386
|
+
runCount: response.runCount,
|
|
387
|
+
ctx,
|
|
388
|
+
});
|
|
389
|
+
const runs = await handleBatchTaskRunExecutionResultV2(result.items);
|
|
390
|
+
return {
|
|
391
|
+
id: result.id,
|
|
392
|
+
runs,
|
|
393
|
+
};
|
|
471
394
|
}, {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
395
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
396
|
+
attributes: {
|
|
397
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
398
|
+
},
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
// Stream path: convert to AsyncIterable and transform
|
|
403
|
+
const asyncItems = normalizeToAsyncIterable(items);
|
|
404
|
+
const transformedItems = transformBatchItemsStreamForWait(asyncItems, options);
|
|
405
|
+
return await tracer_js_1.tracer.startActiveSpan("batch.triggerAndWait()", async (span) => {
|
|
406
|
+
// Execute streaming 2-phase batch
|
|
407
|
+
const response = await executeBatchTwoPhaseStreaming(apiClient, transformedItems, {
|
|
408
|
+
parentRunId: ctx.run.id,
|
|
409
|
+
resumeParentOnCompletion: true,
|
|
410
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
411
|
+
spanParentAsLink: false, // Waiting: child runs share parent's trace ID
|
|
412
|
+
}, requestOptions);
|
|
413
|
+
span.setAttribute("batchId", response.id);
|
|
414
|
+
span.setAttribute("runCount", response.runCount);
|
|
415
|
+
const result = await v3_1.runtime.waitForBatch({
|
|
416
|
+
id: response.id,
|
|
417
|
+
runCount: response.runCount,
|
|
418
|
+
ctx,
|
|
419
|
+
});
|
|
420
|
+
const runs = await handleBatchTaskRunExecutionResultV2(result.items);
|
|
421
|
+
return {
|
|
422
|
+
id: result.id,
|
|
423
|
+
runs,
|
|
424
|
+
};
|
|
425
|
+
}, {
|
|
426
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
427
|
+
attributes: {
|
|
428
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
// Implementation
|
|
434
|
+
async function batchTriggerTasks(...args) {
|
|
435
|
+
const [items, options, requestOptions] = args;
|
|
436
|
+
const apiClient = v3_1.apiClientManager.clientOrThrow(requestOptions?.clientConfig);
|
|
437
|
+
// Check if items is an array or a stream
|
|
438
|
+
if (Array.isArray(items)) {
|
|
439
|
+
// Array path: existing logic
|
|
440
|
+
const ndJsonItems = await Promise.all(items.map(async (item, index) => {
|
|
441
|
+
const taskMetadata = v3_1.resourceCatalog.getTask(item.task.id);
|
|
442
|
+
const parsedPayload = taskMetadata?.fns.parsePayload
|
|
443
|
+
? await taskMetadata?.fns.parsePayload(item.payload)
|
|
444
|
+
: item.payload;
|
|
445
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
446
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
447
|
+
return {
|
|
448
|
+
index,
|
|
449
|
+
task: item.task.id,
|
|
450
|
+
payload: payloadPacket.data,
|
|
451
|
+
options: {
|
|
452
|
+
queue: item.options?.queue ? { name: item.options.queue } : undefined,
|
|
453
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
454
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
455
|
+
payloadType: payloadPacket.dataType,
|
|
456
|
+
delay: item.options?.delay,
|
|
457
|
+
ttl: item.options?.ttl,
|
|
458
|
+
tags: item.options?.tags,
|
|
459
|
+
maxAttempts: item.options?.maxAttempts,
|
|
460
|
+
metadata: item.options?.metadata,
|
|
461
|
+
maxDuration: item.options?.maxDuration,
|
|
462
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
463
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
464
|
+
machine: item.options?.machine,
|
|
465
|
+
priority: item.options?.priority,
|
|
466
|
+
region: item.options?.region,
|
|
467
|
+
lockToVersion: item.options?.version ?? (0, v3_1.getEnvVar)("TRIGGER_VERSION"),
|
|
468
|
+
debounce: item.options?.debounce,
|
|
469
|
+
},
|
|
470
|
+
};
|
|
471
|
+
}));
|
|
472
|
+
// Execute 2-phase batch
|
|
473
|
+
const response = await tracer_js_1.tracer.startActiveSpan("batch.triggerByTask()", async (span) => {
|
|
474
|
+
const result = await executeBatchTwoPhase(apiClient, ndJsonItems, {
|
|
475
|
+
parentRunId: v3_1.taskContext.ctx?.run.id,
|
|
476
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
477
|
+
spanParentAsLink: true, // Fire-and-forget: child runs get separate trace IDs
|
|
478
|
+
}, requestOptions);
|
|
479
|
+
span.setAttribute("batchId", result.id);
|
|
480
|
+
span.setAttribute("runCount", result.runCount);
|
|
481
|
+
return result;
|
|
482
|
+
}, {
|
|
483
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
484
|
+
attributes: {
|
|
485
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
486
|
+
},
|
|
487
|
+
});
|
|
488
|
+
const handle = {
|
|
489
|
+
batchId: response.id,
|
|
478
490
|
runCount: response.runCount,
|
|
479
|
-
|
|
491
|
+
publicAccessToken: response.publicAccessToken,
|
|
492
|
+
};
|
|
493
|
+
return handle;
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
// Stream path: convert to AsyncIterable and transform
|
|
497
|
+
const streamItems = items;
|
|
498
|
+
const asyncItems = normalizeToAsyncIterable(streamItems);
|
|
499
|
+
const transformedItems = transformBatchByTaskItemsStream(asyncItems, options);
|
|
500
|
+
// Execute streaming 2-phase batch
|
|
501
|
+
const response = await tracer_js_1.tracer.startActiveSpan("batch.triggerByTask()", async (span) => {
|
|
502
|
+
const result = await executeBatchTwoPhaseStreaming(apiClient, transformedItems, {
|
|
503
|
+
parentRunId: v3_1.taskContext.ctx?.run.id,
|
|
504
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
505
|
+
spanParentAsLink: true, // Fire-and-forget: child runs get separate trace IDs
|
|
506
|
+
}, requestOptions);
|
|
507
|
+
span.setAttribute("batchId", result.id);
|
|
508
|
+
span.setAttribute("runCount", result.runCount);
|
|
509
|
+
return result;
|
|
510
|
+
}, {
|
|
511
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
512
|
+
attributes: {
|
|
513
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
514
|
+
},
|
|
480
515
|
});
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
516
|
+
const handle = {
|
|
517
|
+
batchId: response.id,
|
|
518
|
+
runCount: response.runCount,
|
|
519
|
+
publicAccessToken: response.publicAccessToken,
|
|
485
520
|
};
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
attributes: {
|
|
489
|
-
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
490
|
-
},
|
|
491
|
-
});
|
|
521
|
+
return handle;
|
|
522
|
+
}
|
|
492
523
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
* @param {TriggerApiRequestOptions} [requestOptions] - Optional API request configuration
|
|
501
|
-
*
|
|
502
|
-
* @returns {Promise<BatchByIdResult<TTask>>} A promise that resolves with the batch results, including
|
|
503
|
-
* success/failure status and strongly-typed outputs for each task
|
|
504
|
-
*
|
|
505
|
-
* @throws {Error} If called outside of a task.run() context
|
|
506
|
-
* @throws {Error} If no API client is configured
|
|
507
|
-
*
|
|
508
|
-
* @example
|
|
509
|
-
* ```ts
|
|
510
|
-
* import { batch, task } from "@trigger.dev/sdk/v3";
|
|
511
|
-
*
|
|
512
|
-
* export const parentTask = task({
|
|
513
|
-
* id: "parent-task",
|
|
514
|
-
* run: async (payload: string) => {
|
|
515
|
-
* const results = await batch.triggerAndWait<typeof childTask1 | typeof childTask2>([
|
|
516
|
-
* {
|
|
517
|
-
* id: "child-task-1",
|
|
518
|
-
* payload: { foo: "World" },
|
|
519
|
-
* options: {
|
|
520
|
-
* queue: "default",
|
|
521
|
-
* delay: "5m",
|
|
522
|
-
* tags: ["batch", "child1"]
|
|
523
|
-
* }
|
|
524
|
-
* },
|
|
525
|
-
* {
|
|
526
|
-
* id: "child-task-2",
|
|
527
|
-
* payload: { bar: 42 }
|
|
528
|
-
* }
|
|
529
|
-
* ]);
|
|
530
|
-
*
|
|
531
|
-
* // Type-safe result handling
|
|
532
|
-
* for (const result of results) {
|
|
533
|
-
* if (result.ok) {
|
|
534
|
-
* switch (result.taskIdentifier) {
|
|
535
|
-
* case "child-task-1":
|
|
536
|
-
* console.log("Child task 1 output:", result.output); // string type
|
|
537
|
-
* break;
|
|
538
|
-
* case "child-task-2":
|
|
539
|
-
* console.log("Child task 2 output:", result.output); // number type
|
|
540
|
-
* break;
|
|
541
|
-
* }
|
|
542
|
-
* } else {
|
|
543
|
-
* console.error("Task failed:", result.error);
|
|
544
|
-
* }
|
|
545
|
-
* }
|
|
546
|
-
* }
|
|
547
|
-
* });
|
|
548
|
-
* ```
|
|
549
|
-
*
|
|
550
|
-
* @description
|
|
551
|
-
* Each task item in the array can include:
|
|
552
|
-
* - `id`: The task identifier (must match one of the tasks in the union type)
|
|
553
|
-
* - `payload`: Strongly-typed payload matching the task's input type
|
|
554
|
-
* - `options`: Optional task-specific settings including:
|
|
555
|
-
* - `queue`: Specify a queue for the task
|
|
556
|
-
* - `concurrencyKey`: Control concurrent execution
|
|
557
|
-
* - `delay`: Delay before task execution
|
|
558
|
-
* - `ttl`: Time-to-live for the task
|
|
559
|
-
* - `tags`: Array of tags for the task
|
|
560
|
-
* - `maxAttempts`: Maximum retry attempts
|
|
561
|
-
* - `metadata`: Additional metadata
|
|
562
|
-
* - `maxDuration`: Maximum execution duration
|
|
563
|
-
*
|
|
564
|
-
* The function provides full type safety for:
|
|
565
|
-
* - Task IDs
|
|
566
|
-
* - Payload types
|
|
567
|
-
* - Return value types
|
|
568
|
-
* - Error handling
|
|
569
|
-
*/
|
|
570
|
-
async function batchTriggerTasks(items, options, requestOptions) {
|
|
524
|
+
// Implementation
|
|
525
|
+
async function batchTriggerAndWaitTasks(...args) {
|
|
526
|
+
const [items, options, requestOptions] = args;
|
|
527
|
+
const ctx = v3_1.taskContext.ctx;
|
|
528
|
+
if (!ctx) {
|
|
529
|
+
throw new Error("batchTriggerAndWait can only be used from inside a task.run()");
|
|
530
|
+
}
|
|
571
531
|
const apiClient = v3_1.apiClientManager.clientOrThrow(requestOptions?.clientConfig);
|
|
572
|
-
|
|
573
|
-
|
|
532
|
+
// Check if items is an array or a stream
|
|
533
|
+
if (Array.isArray(items)) {
|
|
534
|
+
// Array path: existing logic
|
|
535
|
+
const ndJsonItems = await Promise.all(items.map(async (item, index) => {
|
|
574
536
|
const taskMetadata = v3_1.resourceCatalog.getTask(item.task.id);
|
|
575
537
|
const parsedPayload = taskMetadata?.fns.parsePayload
|
|
576
538
|
? await taskMetadata?.fns.parsePayload(item.payload)
|
|
@@ -578,9 +540,11 @@ async function batchTriggerTasks(items, options, requestOptions) {
|
|
|
578
540
|
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
579
541
|
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
580
542
|
return {
|
|
543
|
+
index,
|
|
581
544
|
task: item.task.id,
|
|
582
545
|
payload: payloadPacket.data,
|
|
583
546
|
options: {
|
|
547
|
+
lockToVersion: v3_1.taskContext.worker?.version,
|
|
584
548
|
queue: item.options?.queue ? { name: item.options.queue } : undefined,
|
|
585
549
|
concurrencyKey: item.options?.concurrencyKey,
|
|
586
550
|
test: v3_1.taskContext.ctx?.run.isTest,
|
|
@@ -596,176 +560,458 @@ async function batchTriggerTasks(items, options, requestOptions) {
|
|
|
596
560
|
machine: item.options?.machine,
|
|
597
561
|
priority: item.options?.priority,
|
|
598
562
|
region: item.options?.region,
|
|
599
|
-
|
|
563
|
+
debounce: item.options?.debounce,
|
|
600
564
|
},
|
|
601
565
|
};
|
|
602
|
-
}))
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
566
|
+
}));
|
|
567
|
+
return await tracer_js_1.tracer.startActiveSpan("batch.triggerByTaskAndWait()", async (span) => {
|
|
568
|
+
// Execute 2-phase batch
|
|
569
|
+
const response = await executeBatchTwoPhase(apiClient, ndJsonItems, {
|
|
570
|
+
parentRunId: ctx.run.id,
|
|
571
|
+
resumeParentOnCompletion: true,
|
|
572
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
573
|
+
spanParentAsLink: false, // Waiting: child runs share parent's trace ID
|
|
574
|
+
}, requestOptions);
|
|
575
|
+
span.setAttribute("batchId", response.id);
|
|
576
|
+
span.setAttribute("runCount", response.runCount);
|
|
577
|
+
const result = await v3_1.runtime.waitForBatch({
|
|
578
|
+
id: response.id,
|
|
579
|
+
runCount: response.runCount,
|
|
580
|
+
ctx,
|
|
581
|
+
});
|
|
582
|
+
const runs = await handleBatchTaskRunExecutionResultV2(result.items);
|
|
583
|
+
return {
|
|
584
|
+
id: result.id,
|
|
585
|
+
runs,
|
|
586
|
+
};
|
|
587
|
+
}, {
|
|
588
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
589
|
+
attributes: {
|
|
590
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
591
|
+
},
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
// Stream path: convert to AsyncIterable and transform
|
|
596
|
+
const streamItems = items;
|
|
597
|
+
const asyncItems = normalizeToAsyncIterable(streamItems);
|
|
598
|
+
const transformedItems = transformBatchByTaskItemsStreamForWait(asyncItems, options);
|
|
599
|
+
return await tracer_js_1.tracer.startActiveSpan("batch.triggerByTaskAndWait()", async (span) => {
|
|
600
|
+
// Execute streaming 2-phase batch
|
|
601
|
+
const response = await executeBatchTwoPhaseStreaming(apiClient, transformedItems, {
|
|
602
|
+
parentRunId: ctx.run.id,
|
|
603
|
+
resumeParentOnCompletion: true,
|
|
604
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
605
|
+
spanParentAsLink: false, // Waiting: child runs share parent's trace ID
|
|
606
|
+
}, requestOptions);
|
|
607
|
+
span.setAttribute("batchId", response.id);
|
|
608
|
+
span.setAttribute("runCount", response.runCount);
|
|
609
|
+
const result = await v3_1.runtime.waitForBatch({
|
|
610
|
+
id: response.id,
|
|
611
|
+
runCount: response.runCount,
|
|
612
|
+
ctx,
|
|
613
|
+
});
|
|
614
|
+
const runs = await handleBatchTaskRunExecutionResultV2(result.items);
|
|
615
|
+
return {
|
|
616
|
+
id: result.id,
|
|
617
|
+
runs,
|
|
618
|
+
};
|
|
619
|
+
}, {
|
|
620
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
621
|
+
attributes: {
|
|
622
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
623
|
+
},
|
|
624
|
+
});
|
|
625
|
+
}
|
|
629
626
|
}
|
|
630
627
|
/**
|
|
631
|
-
*
|
|
632
|
-
*
|
|
628
|
+
* Helper function that executes a 2-phase batch trigger:
|
|
629
|
+
* 1. Creates the batch record with expected run count
|
|
630
|
+
* 2. Streams items as NDJSON to the server
|
|
633
631
|
*
|
|
634
|
-
* @
|
|
635
|
-
*
|
|
636
|
-
* @param
|
|
637
|
-
* @param
|
|
632
|
+
* @param apiClient - The API client instance
|
|
633
|
+
* @param items - Array of batch items
|
|
634
|
+
* @param options - Batch options including trace context settings
|
|
635
|
+
* @param options.spanParentAsLink - If true, child runs will have separate trace IDs with a link to parent.
|
|
636
|
+
* Use true for batchTrigger (fire-and-forget), false for batchTriggerAndWait.
|
|
637
|
+
* @param requestOptions - Optional request options
|
|
638
|
+
* @internal
|
|
639
|
+
*/
|
|
640
|
+
async function executeBatchTwoPhase(apiClient, items, options, requestOptions) {
|
|
641
|
+
let batch;
|
|
642
|
+
try {
|
|
643
|
+
// Phase 1: Create batch
|
|
644
|
+
batch = await apiClient.createBatch({
|
|
645
|
+
runCount: items.length,
|
|
646
|
+
parentRunId: options.parentRunId,
|
|
647
|
+
resumeParentOnCompletion: options.resumeParentOnCompletion,
|
|
648
|
+
idempotencyKey: options.idempotencyKey,
|
|
649
|
+
}, { spanParentAsLink: options.spanParentAsLink }, requestOptions);
|
|
650
|
+
}
|
|
651
|
+
catch (error) {
|
|
652
|
+
// Wrap with context about which phase failed
|
|
653
|
+
throw new BatchTriggerError(`Failed to create batch with ${items.length} items`, {
|
|
654
|
+
cause: error,
|
|
655
|
+
phase: "create",
|
|
656
|
+
itemCount: items.length,
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
// If the batch was cached (idempotent replay), skip streaming items
|
|
660
|
+
if (!batch.isCached) {
|
|
661
|
+
try {
|
|
662
|
+
// Phase 2: Stream items
|
|
663
|
+
await apiClient.streamBatchItems(batch.id, items, requestOptions);
|
|
664
|
+
}
|
|
665
|
+
catch (error) {
|
|
666
|
+
// Wrap with context about which phase failed and include batch ID
|
|
667
|
+
throw new BatchTriggerError(`Failed to stream items for batch ${batch.id} (${items.length} items)`, { cause: error, phase: "stream", batchId: batch.id, itemCount: items.length });
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
return {
|
|
671
|
+
id: batch.id,
|
|
672
|
+
runCount: batch.runCount,
|
|
673
|
+
publicAccessToken: batch.publicAccessToken,
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Error thrown when batch trigger operations fail.
|
|
678
|
+
* Includes context about which phase failed and the batch details.
|
|
679
|
+
*/
|
|
680
|
+
class BatchTriggerError extends Error {
|
|
681
|
+
phase;
|
|
682
|
+
batchId;
|
|
683
|
+
itemCount;
|
|
684
|
+
constructor(message, options) {
|
|
685
|
+
super(message, { cause: options.cause });
|
|
686
|
+
this.name = "BatchTriggerError";
|
|
687
|
+
this.phase = options.phase;
|
|
688
|
+
this.batchId = options.batchId;
|
|
689
|
+
this.itemCount = options.itemCount;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
exports.BatchTriggerError = BatchTriggerError;
|
|
693
|
+
/**
|
|
694
|
+
* Execute a streaming 2-phase batch trigger where items are streamed from an AsyncIterable.
|
|
695
|
+
* Unlike executeBatchTwoPhase, this doesn't know the count upfront.
|
|
638
696
|
*
|
|
639
|
-
* @
|
|
640
|
-
*
|
|
697
|
+
* @param apiClient - The API client instance
|
|
698
|
+
* @param items - AsyncIterable of batch items
|
|
699
|
+
* @param options - Batch options including trace context settings
|
|
700
|
+
* @param options.spanParentAsLink - If true, child runs will have separate trace IDs with a link to parent.
|
|
701
|
+
* Use true for batchTrigger (fire-and-forget), false for batchTriggerAndWait.
|
|
702
|
+
* @param requestOptions - Optional request options
|
|
703
|
+
* @internal
|
|
704
|
+
*/
|
|
705
|
+
async function executeBatchTwoPhaseStreaming(apiClient, items, options, requestOptions) {
|
|
706
|
+
// For streaming, we need to buffer items to get the count first
|
|
707
|
+
// This is because createBatch requires runCount upfront
|
|
708
|
+
// In the future, we could add a streaming-first endpoint that doesn't require this
|
|
709
|
+
const itemsArray = [];
|
|
710
|
+
for await (const item of items) {
|
|
711
|
+
itemsArray.push(item);
|
|
712
|
+
}
|
|
713
|
+
// Now we can use the regular 2-phase approach
|
|
714
|
+
return executeBatchTwoPhase(apiClient, itemsArray, options, requestOptions);
|
|
715
|
+
}
|
|
716
|
+
// ============================================================================
|
|
717
|
+
// Streaming Helpers
|
|
718
|
+
// ============================================================================
|
|
719
|
+
/**
|
|
720
|
+
* Type guard to check if a value is an AsyncIterable
|
|
721
|
+
*/
|
|
722
|
+
function isAsyncIterable(value) {
|
|
723
|
+
return (value != null &&
|
|
724
|
+
typeof value === "object" &&
|
|
725
|
+
Symbol.asyncIterator in value &&
|
|
726
|
+
typeof value[Symbol.asyncIterator] === "function");
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Type guard to check if a value is a ReadableStream
|
|
730
|
+
*/
|
|
731
|
+
function isReadableStream(value) {
|
|
732
|
+
return (value != null &&
|
|
733
|
+
typeof value === "object" &&
|
|
734
|
+
"getReader" in value &&
|
|
735
|
+
typeof value.getReader === "function");
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Convert a ReadableStream to an AsyncIterable.
|
|
739
|
+
* Properly cancels the stream when the consumer terminates early.
|
|
641
740
|
*
|
|
642
|
-
* @
|
|
643
|
-
|
|
741
|
+
* @internal Exported for testing purposes
|
|
742
|
+
*/
|
|
743
|
+
async function* readableStreamToAsyncIterable(stream) {
|
|
744
|
+
const reader = stream.getReader();
|
|
745
|
+
try {
|
|
746
|
+
while (true) {
|
|
747
|
+
const { done, value } = await reader.read();
|
|
748
|
+
if (done)
|
|
749
|
+
break;
|
|
750
|
+
yield value;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
finally {
|
|
754
|
+
try {
|
|
755
|
+
await reader.cancel();
|
|
756
|
+
}
|
|
757
|
+
catch {
|
|
758
|
+
// Ignore errors - stream might already be errored or closed
|
|
759
|
+
}
|
|
760
|
+
reader.releaseLock();
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Normalize stream input to AsyncIterable
|
|
765
|
+
*/
|
|
766
|
+
function normalizeToAsyncIterable(input) {
|
|
767
|
+
if (isReadableStream(input)) {
|
|
768
|
+
return readableStreamToAsyncIterable(input);
|
|
769
|
+
}
|
|
770
|
+
return input;
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Transform a stream of BatchByIdItem to BatchItemNDJSON format.
|
|
774
|
+
* Handles payload serialization and idempotency key generation.
|
|
644
775
|
*
|
|
645
|
-
* @
|
|
646
|
-
|
|
647
|
-
*
|
|
776
|
+
* @internal
|
|
777
|
+
*/
|
|
778
|
+
async function* transformBatchItemsStream(items, options) {
|
|
779
|
+
let index = 0;
|
|
780
|
+
for await (const item of items) {
|
|
781
|
+
const taskMetadata = v3_1.resourceCatalog.getTask(item.id);
|
|
782
|
+
const parsedPayload = taskMetadata?.fns.parsePayload
|
|
783
|
+
? await taskMetadata?.fns.parsePayload(item.payload)
|
|
784
|
+
: item.payload;
|
|
785
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
786
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
787
|
+
yield {
|
|
788
|
+
index: index++,
|
|
789
|
+
task: item.id,
|
|
790
|
+
payload: payloadPacket.data,
|
|
791
|
+
options: {
|
|
792
|
+
queue: item.options?.queue ? { name: item.options.queue } : undefined,
|
|
793
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
794
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
795
|
+
payloadType: payloadPacket.dataType,
|
|
796
|
+
delay: item.options?.delay,
|
|
797
|
+
ttl: item.options?.ttl,
|
|
798
|
+
tags: item.options?.tags,
|
|
799
|
+
maxAttempts: item.options?.maxAttempts,
|
|
800
|
+
metadata: item.options?.metadata,
|
|
801
|
+
maxDuration: item.options?.maxDuration,
|
|
802
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
803
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
804
|
+
machine: item.options?.machine,
|
|
805
|
+
priority: item.options?.priority,
|
|
806
|
+
region: item.options?.region,
|
|
807
|
+
lockToVersion: item.options?.version ?? (0, v3_1.getEnvVar)("TRIGGER_VERSION"),
|
|
808
|
+
debounce: item.options?.debounce,
|
|
809
|
+
},
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Transform a stream of BatchByIdAndWaitItem to BatchItemNDJSON format for triggerAndWait.
|
|
815
|
+
* Uses the current worker version for lockToVersion.
|
|
648
816
|
*
|
|
649
|
-
*
|
|
650
|
-
|
|
651
|
-
*
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
817
|
+
* @internal
|
|
818
|
+
*/
|
|
819
|
+
async function* transformBatchItemsStreamForWait(items, options) {
|
|
820
|
+
let index = 0;
|
|
821
|
+
for await (const item of items) {
|
|
822
|
+
const taskMetadata = v3_1.resourceCatalog.getTask(item.id);
|
|
823
|
+
const parsedPayload = taskMetadata?.fns.parsePayload
|
|
824
|
+
? await taskMetadata?.fns.parsePayload(item.payload)
|
|
825
|
+
: item.payload;
|
|
826
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
827
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
828
|
+
yield {
|
|
829
|
+
index: index++,
|
|
830
|
+
task: item.id,
|
|
831
|
+
payload: payloadPacket.data,
|
|
832
|
+
options: {
|
|
833
|
+
lockToVersion: v3_1.taskContext.worker?.version,
|
|
834
|
+
queue: item.options?.queue ? { name: item.options.queue } : undefined,
|
|
835
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
836
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
837
|
+
payloadType: payloadPacket.dataType,
|
|
838
|
+
delay: item.options?.delay,
|
|
839
|
+
ttl: item.options?.ttl,
|
|
840
|
+
tags: item.options?.tags,
|
|
841
|
+
maxAttempts: item.options?.maxAttempts,
|
|
842
|
+
metadata: item.options?.metadata,
|
|
843
|
+
maxDuration: item.options?.maxDuration,
|
|
844
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
845
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
846
|
+
machine: item.options?.machine,
|
|
847
|
+
priority: item.options?.priority,
|
|
848
|
+
region: item.options?.region,
|
|
849
|
+
debounce: item.options?.debounce,
|
|
850
|
+
},
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Transform a stream of BatchByTaskItem to BatchItemNDJSON format.
|
|
667
856
|
*
|
|
668
|
-
*
|
|
669
|
-
|
|
670
|
-
*
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
857
|
+
* @internal
|
|
858
|
+
*/
|
|
859
|
+
async function* transformBatchByTaskItemsStream(items, options) {
|
|
860
|
+
let index = 0;
|
|
861
|
+
for await (const item of items) {
|
|
862
|
+
const taskMetadata = v3_1.resourceCatalog.getTask(item.task.id);
|
|
863
|
+
const parsedPayload = taskMetadata?.fns.parsePayload
|
|
864
|
+
? await taskMetadata?.fns.parsePayload(item.payload)
|
|
865
|
+
: item.payload;
|
|
866
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
867
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
868
|
+
yield {
|
|
869
|
+
index: index++,
|
|
870
|
+
task: item.task.id,
|
|
871
|
+
payload: payloadPacket.data,
|
|
872
|
+
options: {
|
|
873
|
+
queue: item.options?.queue ? { name: item.options.queue } : undefined,
|
|
874
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
875
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
876
|
+
payloadType: payloadPacket.dataType,
|
|
877
|
+
delay: item.options?.delay,
|
|
878
|
+
ttl: item.options?.ttl,
|
|
879
|
+
tags: item.options?.tags,
|
|
880
|
+
maxAttempts: item.options?.maxAttempts,
|
|
881
|
+
metadata: item.options?.metadata,
|
|
882
|
+
maxDuration: item.options?.maxDuration,
|
|
883
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
884
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
885
|
+
machine: item.options?.machine,
|
|
886
|
+
priority: item.options?.priority,
|
|
887
|
+
region: item.options?.region,
|
|
888
|
+
lockToVersion: item.options?.version ?? (0, v3_1.getEnvVar)("TRIGGER_VERSION"),
|
|
889
|
+
debounce: item.options?.debounce,
|
|
890
|
+
},
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Transform a stream of BatchByTaskAndWaitItem to BatchItemNDJSON format for triggerAndWait.
|
|
686
896
|
*
|
|
687
|
-
* @
|
|
688
|
-
|
|
689
|
-
*
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
897
|
+
* @internal
|
|
898
|
+
*/
|
|
899
|
+
async function* transformBatchByTaskItemsStreamForWait(items, options) {
|
|
900
|
+
let index = 0;
|
|
901
|
+
for await (const item of items) {
|
|
902
|
+
const taskMetadata = v3_1.resourceCatalog.getTask(item.task.id);
|
|
903
|
+
const parsedPayload = taskMetadata?.fns.parsePayload
|
|
904
|
+
? await taskMetadata?.fns.parsePayload(item.payload)
|
|
905
|
+
: item.payload;
|
|
906
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
907
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
908
|
+
yield {
|
|
909
|
+
index: index++,
|
|
910
|
+
task: item.task.id,
|
|
911
|
+
payload: payloadPacket.data,
|
|
912
|
+
options: {
|
|
913
|
+
lockToVersion: v3_1.taskContext.worker?.version,
|
|
914
|
+
queue: item.options?.queue ? { name: item.options.queue } : undefined,
|
|
915
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
916
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
917
|
+
payloadType: payloadPacket.dataType,
|
|
918
|
+
delay: item.options?.delay,
|
|
919
|
+
ttl: item.options?.ttl,
|
|
920
|
+
tags: item.options?.tags,
|
|
921
|
+
maxAttempts: item.options?.maxAttempts,
|
|
922
|
+
metadata: item.options?.metadata,
|
|
923
|
+
maxDuration: item.options?.maxDuration,
|
|
924
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
925
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
926
|
+
machine: item.options?.machine,
|
|
927
|
+
priority: item.options?.priority,
|
|
928
|
+
region: item.options?.region,
|
|
929
|
+
debounce: item.options?.debounce,
|
|
930
|
+
},
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Transform a stream of BatchItem (single task type) to BatchItemNDJSON format.
|
|
700
936
|
*
|
|
701
|
-
*
|
|
702
|
-
* - Task IDs
|
|
703
|
-
* - Payload types
|
|
704
|
-
* - Return value types
|
|
705
|
-
* - Error handling
|
|
937
|
+
* @internal
|
|
706
938
|
*/
|
|
707
|
-
async function
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
939
|
+
async function* transformSingleTaskBatchItemsStream(taskIdentifier, items, parsePayload, options, queue) {
|
|
940
|
+
let index = 0;
|
|
941
|
+
for await (const item of items) {
|
|
942
|
+
const parsedPayload = parsePayload ? await parsePayload(item.payload) : item.payload;
|
|
943
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
944
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
945
|
+
yield {
|
|
946
|
+
index: index++,
|
|
947
|
+
task: taskIdentifier,
|
|
948
|
+
payload: payloadPacket.data,
|
|
949
|
+
options: {
|
|
950
|
+
queue: item.options?.queue
|
|
951
|
+
? { name: item.options.queue }
|
|
952
|
+
: queue
|
|
953
|
+
? { name: queue }
|
|
954
|
+
: undefined,
|
|
955
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
956
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
957
|
+
payloadType: payloadPacket.dataType,
|
|
958
|
+
delay: item.options?.delay,
|
|
959
|
+
ttl: item.options?.ttl,
|
|
960
|
+
tags: item.options?.tags,
|
|
961
|
+
maxAttempts: item.options?.maxAttempts,
|
|
962
|
+
metadata: item.options?.metadata,
|
|
963
|
+
maxDuration: item.options?.maxDuration,
|
|
964
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
965
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
966
|
+
machine: item.options?.machine,
|
|
967
|
+
priority: item.options?.priority,
|
|
968
|
+
region: item.options?.region,
|
|
969
|
+
lockToVersion: item.options?.version ?? (0, v3_1.getEnvVar)("TRIGGER_VERSION"),
|
|
970
|
+
debounce: item.options?.debounce,
|
|
971
|
+
},
|
|
972
|
+
};
|
|
711
973
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
span.setAttribute("batchId", response.id);
|
|
752
|
-
span.setAttribute("runCount", response.runCount);
|
|
753
|
-
const result = await v3_1.runtime.waitForBatch({
|
|
754
|
-
id: response.id,
|
|
755
|
-
runCount: response.runCount,
|
|
756
|
-
ctx,
|
|
757
|
-
});
|
|
758
|
-
const runs = await handleBatchTaskRunExecutionResultV2(result.items);
|
|
759
|
-
return {
|
|
760
|
-
id: result.id,
|
|
761
|
-
runs,
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* Transform a stream of BatchTriggerAndWaitItem (single task type) to BatchItemNDJSON format.
|
|
977
|
+
*
|
|
978
|
+
* @internal
|
|
979
|
+
*/
|
|
980
|
+
async function* transformSingleTaskBatchItemsStreamForWait(taskIdentifier, items, parsePayload, options, queue) {
|
|
981
|
+
let index = 0;
|
|
982
|
+
for await (const item of items) {
|
|
983
|
+
const parsedPayload = parsePayload ? await parsePayload(item.payload) : item.payload;
|
|
984
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
985
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
986
|
+
yield {
|
|
987
|
+
index: index++,
|
|
988
|
+
task: taskIdentifier,
|
|
989
|
+
payload: payloadPacket.data,
|
|
990
|
+
options: {
|
|
991
|
+
lockToVersion: v3_1.taskContext.worker?.version,
|
|
992
|
+
queue: item.options?.queue
|
|
993
|
+
? { name: item.options.queue }
|
|
994
|
+
: queue
|
|
995
|
+
? { name: queue }
|
|
996
|
+
: undefined,
|
|
997
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
998
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
999
|
+
payloadType: payloadPacket.dataType,
|
|
1000
|
+
delay: item.options?.delay,
|
|
1001
|
+
ttl: item.options?.ttl,
|
|
1002
|
+
tags: item.options?.tags,
|
|
1003
|
+
maxAttempts: item.options?.maxAttempts,
|
|
1004
|
+
metadata: item.options?.metadata,
|
|
1005
|
+
maxDuration: item.options?.maxDuration,
|
|
1006
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
1007
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
1008
|
+
machine: item.options?.machine,
|
|
1009
|
+
priority: item.options?.priority,
|
|
1010
|
+
region: item.options?.region,
|
|
1011
|
+
debounce: item.options?.debounce,
|
|
1012
|
+
},
|
|
762
1013
|
};
|
|
763
|
-
}
|
|
764
|
-
kind: api_1.SpanKind.PRODUCER,
|
|
765
|
-
attributes: {
|
|
766
|
-
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
767
|
-
},
|
|
768
|
-
});
|
|
1014
|
+
}
|
|
769
1015
|
}
|
|
770
1016
|
async function trigger_internal(name, id, payload, parsePayload, options, requestOptions) {
|
|
771
1017
|
const apiClient = v3_1.apiClientManager.clientOrThrow(requestOptions?.clientConfig);
|
|
@@ -791,6 +1037,7 @@ async function trigger_internal(name, id, payload, parsePayload, options, reques
|
|
|
791
1037
|
priority: options?.priority,
|
|
792
1038
|
region: options?.region,
|
|
793
1039
|
lockToVersion: options?.version ?? (0, v3_1.getEnvVar)("TRIGGER_VERSION"),
|
|
1040
|
+
debounce: options?.debounce,
|
|
794
1041
|
},
|
|
795
1042
|
}, {
|
|
796
1043
|
spanParentAsLink: true,
|
|
@@ -812,12 +1059,15 @@ async function trigger_internal(name, id, payload, parsePayload, options, reques
|
|
|
812
1059
|
async function batchTrigger_internal(name, taskIdentifier, items, options, parsePayload, requestOptions, queue) {
|
|
813
1060
|
const apiClient = v3_1.apiClientManager.clientOrThrow(requestOptions?.clientConfig);
|
|
814
1061
|
const ctx = v3_1.taskContext.ctx;
|
|
815
|
-
|
|
816
|
-
|
|
1062
|
+
// Check if items is an array or a stream
|
|
1063
|
+
if (Array.isArray(items)) {
|
|
1064
|
+
// Prepare items as BatchItemNDJSON
|
|
1065
|
+
const ndJsonItems = await Promise.all(items.map(async (item, index) => {
|
|
817
1066
|
const parsedPayload = parsePayload ? await parsePayload(item.payload) : item.payload;
|
|
818
1067
|
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
819
1068
|
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
820
1069
|
return {
|
|
1070
|
+
index,
|
|
821
1071
|
task: taskIdentifier,
|
|
822
1072
|
payload: payloadPacket.data,
|
|
823
1073
|
options: {
|
|
@@ -843,33 +1093,75 @@ async function batchTrigger_internal(name, taskIdentifier, items, options, parse
|
|
|
843
1093
|
lockToVersion: item.options?.version ?? (0, v3_1.getEnvVar)("TRIGGER_VERSION"),
|
|
844
1094
|
},
|
|
845
1095
|
};
|
|
846
|
-
}))
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1096
|
+
}));
|
|
1097
|
+
// Execute 2-phase batch
|
|
1098
|
+
const response = await tracer_js_1.tracer.startActiveSpan(name, async (span) => {
|
|
1099
|
+
const result = await executeBatchTwoPhase(apiClient, ndJsonItems, {
|
|
1100
|
+
parentRunId: ctx?.run.id,
|
|
1101
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
1102
|
+
spanParentAsLink: true, // Fire-and-forget: child runs get separate trace IDs
|
|
1103
|
+
}, requestOptions);
|
|
1104
|
+
span.setAttribute("batchId", result.id);
|
|
1105
|
+
span.setAttribute("runCount", result.runCount);
|
|
1106
|
+
return result;
|
|
1107
|
+
}, {
|
|
1108
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
1109
|
+
attributes: {
|
|
1110
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
1111
|
+
...(0, v3_1.accessoryAttributes)({
|
|
1112
|
+
items: [
|
|
1113
|
+
{
|
|
1114
|
+
text: taskIdentifier,
|
|
1115
|
+
variant: "normal",
|
|
1116
|
+
},
|
|
1117
|
+
],
|
|
1118
|
+
style: "codepath",
|
|
1119
|
+
}),
|
|
1120
|
+
},
|
|
1121
|
+
});
|
|
1122
|
+
const handle = {
|
|
1123
|
+
batchId: response.id,
|
|
1124
|
+
runCount: response.runCount,
|
|
1125
|
+
publicAccessToken: response.publicAccessToken,
|
|
1126
|
+
};
|
|
1127
|
+
return handle;
|
|
1128
|
+
}
|
|
1129
|
+
else {
|
|
1130
|
+
// Stream path: convert to AsyncIterable and transform
|
|
1131
|
+
const asyncItems = normalizeToAsyncIterable(items);
|
|
1132
|
+
const transformedItems = transformSingleTaskBatchItemsStream(taskIdentifier, asyncItems, parsePayload, options, queue);
|
|
1133
|
+
// Execute streaming 2-phase batch
|
|
1134
|
+
const response = await tracer_js_1.tracer.startActiveSpan(name, async (span) => {
|
|
1135
|
+
const result = await executeBatchTwoPhaseStreaming(apiClient, transformedItems, {
|
|
1136
|
+
parentRunId: ctx?.run.id,
|
|
1137
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
1138
|
+
spanParentAsLink: true, // Fire-and-forget: child runs get separate trace IDs
|
|
1139
|
+
}, requestOptions);
|
|
1140
|
+
span.setAttribute("batchId", result.id);
|
|
1141
|
+
span.setAttribute("runCount", result.runCount);
|
|
1142
|
+
return result;
|
|
1143
|
+
}, {
|
|
1144
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
1145
|
+
attributes: {
|
|
1146
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
1147
|
+
...(0, v3_1.accessoryAttributes)({
|
|
1148
|
+
items: [
|
|
1149
|
+
{
|
|
1150
|
+
text: taskIdentifier,
|
|
1151
|
+
variant: "normal",
|
|
1152
|
+
},
|
|
1153
|
+
],
|
|
1154
|
+
style: "codepath",
|
|
1155
|
+
}),
|
|
1156
|
+
},
|
|
1157
|
+
});
|
|
1158
|
+
const handle = {
|
|
1159
|
+
batchId: response.id,
|
|
1160
|
+
runCount: response.runCount,
|
|
1161
|
+
publicAccessToken: response.publicAccessToken,
|
|
1162
|
+
};
|
|
1163
|
+
return handle;
|
|
1164
|
+
}
|
|
873
1165
|
}
|
|
874
1166
|
async function triggerAndWait_internal(name, id, payload, parsePayload, options, requestOptions) {
|
|
875
1167
|
const ctx = v3_1.taskContext.ctx;
|
|
@@ -901,6 +1193,7 @@ async function triggerAndWait_internal(name, id, payload, parsePayload, options,
|
|
|
901
1193
|
machine: options?.machine,
|
|
902
1194
|
priority: options?.priority,
|
|
903
1195
|
region: options?.region,
|
|
1196
|
+
debounce: options?.debounce,
|
|
904
1197
|
},
|
|
905
1198
|
}, {}, requestOptions);
|
|
906
1199
|
span.setAttribute("runId", response.id);
|
|
@@ -931,72 +1224,117 @@ async function batchTriggerAndWait_internal(name, id, items, parsePayload, optio
|
|
|
931
1224
|
throw new Error("batchTriggerAndWait can only be used from inside a task.run()");
|
|
932
1225
|
}
|
|
933
1226
|
const apiClient = v3_1.apiClientManager.clientOrThrow(requestOptions?.clientConfig);
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
|
|
1227
|
+
// Check if items is an array or a stream
|
|
1228
|
+
if (Array.isArray(items)) {
|
|
1229
|
+
// Prepare items as BatchItemNDJSON
|
|
1230
|
+
const ndJsonItems = await Promise.all(items.map(async (item, index) => {
|
|
1231
|
+
const parsedPayload = parsePayload ? await parsePayload(item.payload) : item.payload;
|
|
1232
|
+
const payloadPacket = await (0, v3_1.stringifyIO)(parsedPayload);
|
|
1233
|
+
const batchItemIdempotencyKey = await (0, v3_1.makeIdempotencyKey)((0, v3_1.flattenIdempotencyKey)([options?.idempotencyKey, `${index}`]));
|
|
1234
|
+
return {
|
|
1235
|
+
index,
|
|
1236
|
+
task: id,
|
|
1237
|
+
payload: payloadPacket.data,
|
|
1238
|
+
options: {
|
|
1239
|
+
lockToVersion: v3_1.taskContext.worker?.version,
|
|
1240
|
+
queue: item.options?.queue
|
|
1241
|
+
? { name: item.options.queue }
|
|
1242
|
+
: queue
|
|
1243
|
+
? { name: queue }
|
|
1244
|
+
: undefined,
|
|
1245
|
+
concurrencyKey: item.options?.concurrencyKey,
|
|
1246
|
+
test: v3_1.taskContext.ctx?.run.isTest,
|
|
1247
|
+
payloadType: payloadPacket.dataType,
|
|
1248
|
+
delay: item.options?.delay,
|
|
1249
|
+
ttl: item.options?.ttl,
|
|
1250
|
+
tags: item.options?.tags,
|
|
1251
|
+
maxAttempts: item.options?.maxAttempts,
|
|
1252
|
+
metadata: item.options?.metadata,
|
|
1253
|
+
maxDuration: item.options?.maxDuration,
|
|
1254
|
+
idempotencyKey: (await (0, v3_1.makeIdempotencyKey)(item.options?.idempotencyKey)) ?? batchItemIdempotencyKey,
|
|
1255
|
+
idempotencyKeyTTL: item.options?.idempotencyKeyTTL ?? options?.idempotencyKeyTTL,
|
|
1256
|
+
machine: item.options?.machine,
|
|
1257
|
+
priority: item.options?.priority,
|
|
1258
|
+
region: item.options?.region,
|
|
1259
|
+
},
|
|
1260
|
+
};
|
|
1261
|
+
}));
|
|
1262
|
+
return await tracer_js_1.tracer.startActiveSpan(name, async (span) => {
|
|
1263
|
+
// Execute 2-phase batch
|
|
1264
|
+
const response = await executeBatchTwoPhase(apiClient, ndJsonItems, {
|
|
1265
|
+
parentRunId: ctx.run.id,
|
|
1266
|
+
resumeParentOnCompletion: true,
|
|
1267
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
1268
|
+
spanParentAsLink: false, // Waiting: child runs share parent's trace ID
|
|
1269
|
+
}, requestOptions);
|
|
1270
|
+
span.setAttribute("batchId", response.id);
|
|
1271
|
+
span.setAttribute("runCount", response.runCount);
|
|
1272
|
+
const result = await v3_1.runtime.waitForBatch({
|
|
1273
|
+
id: response.id,
|
|
1274
|
+
runCount: response.runCount,
|
|
1275
|
+
ctx,
|
|
1276
|
+
});
|
|
1277
|
+
const runs = await handleBatchTaskRunExecutionResult(result.items, id);
|
|
1278
|
+
return {
|
|
1279
|
+
id: result.id,
|
|
1280
|
+
runs,
|
|
1281
|
+
};
|
|
970
1282
|
}, {
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1283
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
1284
|
+
attributes: {
|
|
1285
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
1286
|
+
...(0, v3_1.accessoryAttributes)({
|
|
1287
|
+
items: [
|
|
1288
|
+
{
|
|
1289
|
+
text: id,
|
|
1290
|
+
variant: "normal",
|
|
1291
|
+
},
|
|
1292
|
+
],
|
|
1293
|
+
style: "codepath",
|
|
1294
|
+
}),
|
|
1295
|
+
},
|
|
979
1296
|
});
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1297
|
+
}
|
|
1298
|
+
else {
|
|
1299
|
+
// Stream path: convert to AsyncIterable and transform
|
|
1300
|
+
const asyncItems = normalizeToAsyncIterable(items);
|
|
1301
|
+
const transformedItems = transformSingleTaskBatchItemsStreamForWait(id, asyncItems, parsePayload, options, queue);
|
|
1302
|
+
return await tracer_js_1.tracer.startActiveSpan(name, async (span) => {
|
|
1303
|
+
// Execute streaming 2-phase batch
|
|
1304
|
+
const response = await executeBatchTwoPhaseStreaming(apiClient, transformedItems, {
|
|
1305
|
+
parentRunId: ctx.run.id,
|
|
1306
|
+
resumeParentOnCompletion: true,
|
|
1307
|
+
idempotencyKey: await (0, v3_1.makeIdempotencyKey)(options?.idempotencyKey),
|
|
1308
|
+
spanParentAsLink: false, // Waiting: child runs share parent's trace ID
|
|
1309
|
+
}, requestOptions);
|
|
1310
|
+
span.setAttribute("batchId", response.id);
|
|
1311
|
+
span.setAttribute("runCount", response.runCount);
|
|
1312
|
+
const result = await v3_1.runtime.waitForBatch({
|
|
1313
|
+
id: response.id,
|
|
1314
|
+
runCount: response.runCount,
|
|
1315
|
+
ctx,
|
|
1316
|
+
});
|
|
1317
|
+
const runs = await handleBatchTaskRunExecutionResult(result.items, id);
|
|
1318
|
+
return {
|
|
1319
|
+
id: result.id,
|
|
1320
|
+
runs,
|
|
1321
|
+
};
|
|
1322
|
+
}, {
|
|
1323
|
+
kind: api_1.SpanKind.PRODUCER,
|
|
1324
|
+
attributes: {
|
|
1325
|
+
[v3_1.SemanticInternalAttributes.STYLE_ICON]: "trigger",
|
|
1326
|
+
...(0, v3_1.accessoryAttributes)({
|
|
1327
|
+
items: [
|
|
1328
|
+
{
|
|
1329
|
+
text: id,
|
|
1330
|
+
variant: "normal",
|
|
1331
|
+
},
|
|
1332
|
+
],
|
|
1333
|
+
style: "codepath",
|
|
1334
|
+
}),
|
|
1335
|
+
},
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1000
1338
|
}
|
|
1001
1339
|
async function handleBatchTaskRunExecutionResult(items, taskIdentifier) {
|
|
1002
1340
|
const someObjectStoreOutputs = items.some((item) => item.ok && item.outputType === "application/store");
|