trigger.dev 3.0.0-beta.53 → 3.0.0-beta.54

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.
@@ -8,7 +8,7 @@ import { ZodMessageSender } from "@trigger.dev/core/v3/zodMessageHandler";
8
8
  import "source-map-support/register.js";
9
9
 
10
10
  // package.json
11
- var version = "3.0.0-beta.53";
11
+ var version = "3.0.0-beta.54";
12
12
 
13
13
  // src/workers/dev/worker-setup.ts
14
14
  __SETUP_IMPORTED_PROJECT_CONFIG__;
@@ -1085,7 +1085,6 @@ import { randomUUID } from "node:crypto";
1085
1085
  import { readFile } from "node:fs/promises";
1086
1086
  import { createServer } from "node:http";
1087
1087
  import { setTimeout as timeout2 } from "node:timers/promises";
1088
- import { Evt as Evt2 } from "evt";
1089
1088
  var HTTP_SERVER_PORT = Number(process.env.HTTP_SERVER_PORT || getRandomPortNumber());
1090
1089
  var COORDINATOR_HOST = process.env.COORDINATOR_HOST || "127.0.0.1";
1091
1090
  var COORDINATOR_PORT = Number(process.env.COORDINATOR_PORT || 50080);
@@ -1118,14 +1117,13 @@ var ProdWorker = class {
1118
1117
  completed = /* @__PURE__ */ new Set();
1119
1118
  paused = false;
1120
1119
  attemptFriendlyId;
1121
- attemptNumber;
1122
1120
  nextResumeAfter;
1123
1121
  waitForPostStart = false;
1124
1122
  connectionCount = 0;
1125
- restoreNotification = Evt2.create();
1126
1123
  waitForTaskReplay;
1127
1124
  waitForBatchReplay;
1128
1125
  readyForLazyAttemptReplay;
1126
+ submitAttemptCompletionReplay;
1129
1127
  durationResumeFallback;
1130
1128
  #httpPort;
1131
1129
  #backgroundWorker;
@@ -1185,118 +1183,98 @@ var ProdWorker = class {
1185
1183
  }
1186
1184
  }
1187
1185
  // MARK: TASK WAIT
1188
- #waitForTaskHandlerFactory(workerId) {
1189
- return async (message, replayIdempotencyKey) => {
1190
- logger.log("onWaitForTask", { workerId, message });
1191
- if (this.nextResumeAfter) {
1192
- logger.error("Already waiting for resume, skipping wait for task", {
1193
- nextResumeAfter: this.nextResumeAfter
1194
- });
1195
- return;
1186
+ async #waitForTaskHandler(message, replayIdempotencyKey) {
1187
+ const waitForTask = await defaultBackoff.execute(async ({ retry }) => {
1188
+ logger.log("Wait for task with backoff", { retry });
1189
+ if (!this.attemptFriendlyId) {
1190
+ logger.error("Failed to send wait message, attempt friendly ID not set", { message });
1191
+ throw new ExponentialBackoff.StopRetrying("No attempt ID");
1196
1192
  }
1197
- const waitForTask = await defaultBackoff.execute(async ({ retry }) => {
1198
- logger.log("Wait for task with backoff", { retry });
1199
- if (!this.attemptFriendlyId) {
1200
- logger.error("Failed to send wait message, attempt friendly ID not set", { message });
1201
- throw new ExponentialBackoff.StopRetrying("No attempt ID");
1202
- }
1203
- return await this.#coordinatorSocket.socket.timeout(2e4).emitWithAck("WAIT_FOR_TASK", {
1204
- version: "v2",
1205
- friendlyId: message.friendlyId,
1206
- attemptFriendlyId: this.attemptFriendlyId
1207
- });
1193
+ return await this.#coordinatorSocket.socket.timeout(2e4).emitWithAck("WAIT_FOR_TASK", {
1194
+ version: "v2",
1195
+ friendlyId: message.friendlyId,
1196
+ attemptFriendlyId: this.attemptFriendlyId
1208
1197
  });
1209
- if (!waitForTask.success) {
1210
- logger.error("Failed to wait for task with backoff", {
1211
- cause: waitForTask.cause,
1212
- error: waitForTask.error
1213
- });
1214
- this.#emitUnrecoverableError(
1215
- "WaitForTaskFailed",
1216
- `${waitForTask.cause}: ${waitForTask.error}`
1217
- );
1218
- return;
1219
- }
1220
- const { willCheckpointAndRestore } = waitForTask.result;
1221
- await this.#prepareForWait("WAIT_FOR_TASK", willCheckpointAndRestore);
1222
- if (willCheckpointAndRestore) {
1223
- if (!this.waitForTaskReplay) {
1224
- this.waitForTaskReplay = {
1225
- message,
1226
- attempt: 1,
1227
- idempotencyKey: randomUUID()
1228
- };
1229
- } else {
1230
- if (replayIdempotencyKey && replayIdempotencyKey !== this.waitForTaskReplay.idempotencyKey) {
1231
- logger.error(
1232
- "wait for task handler called with mismatched idempotency key, won't overwrite replay request"
1233
- );
1234
- return;
1235
- }
1236
- this.waitForTaskReplay.attempt++;
1198
+ });
1199
+ if (!waitForTask.success) {
1200
+ logger.error("Failed to wait for task with backoff", {
1201
+ cause: waitForTask.cause,
1202
+ error: waitForTask.error
1203
+ });
1204
+ this.#emitUnrecoverableError(
1205
+ "WaitForTaskFailed",
1206
+ `${waitForTask.cause}: ${waitForTask.error}`
1207
+ );
1208
+ return;
1209
+ }
1210
+ const { willCheckpointAndRestore } = waitForTask.result;
1211
+ await this.#prepareForWait("WAIT_FOR_TASK", willCheckpointAndRestore);
1212
+ if (willCheckpointAndRestore) {
1213
+ if (!this.waitForTaskReplay) {
1214
+ this.waitForTaskReplay = {
1215
+ message,
1216
+ attempt: 1,
1217
+ idempotencyKey: randomUUID()
1218
+ };
1219
+ } else {
1220
+ if (replayIdempotencyKey && replayIdempotencyKey !== this.waitForTaskReplay.idempotencyKey) {
1221
+ logger.error(
1222
+ "wait for task handler called with mismatched idempotency key, won't overwrite replay request"
1223
+ );
1224
+ return;
1237
1225
  }
1226
+ this.waitForTaskReplay.attempt++;
1238
1227
  }
1239
- };
1228
+ }
1240
1229
  }
1241
1230
  // MARK: BATCH WAIT
1242
- #waitForBatchHandlerFactory(workerId) {
1243
- return async (message, replayIdempotencyKey) => {
1244
- logger.log("onWaitForBatch", { workerId, message });
1245
- if (this.nextResumeAfter) {
1246
- logger.error("Already waiting for resume, skipping wait for batch", {
1247
- nextResumeAfter: this.nextResumeAfter
1248
- });
1249
- return;
1231
+ async #waitForBatchHandler(message, replayIdempotencyKey) {
1232
+ const waitForBatch = await defaultBackoff.execute(async ({ retry }) => {
1233
+ logger.log("Wait for batch with backoff", { retry });
1234
+ if (!this.attemptFriendlyId) {
1235
+ logger.error("Failed to send wait message, attempt friendly ID not set", { message });
1236
+ throw new ExponentialBackoff.StopRetrying("No attempt ID");
1250
1237
  }
1251
- const waitForBatch = await defaultBackoff.execute(async ({ retry }) => {
1252
- logger.log("Wait for batch with backoff", { retry });
1253
- if (!this.attemptFriendlyId) {
1254
- logger.error("Failed to send wait message, attempt friendly ID not set", { message });
1255
- throw new ExponentialBackoff.StopRetrying("No attempt ID");
1256
- }
1257
- return await this.#coordinatorSocket.socket.timeout(2e4).emitWithAck("WAIT_FOR_BATCH", {
1258
- version: "v2",
1259
- batchFriendlyId: message.batchFriendlyId,
1260
- runFriendlyIds: message.runFriendlyIds,
1261
- attemptFriendlyId: this.attemptFriendlyId
1262
- });
1238
+ return await this.#coordinatorSocket.socket.timeout(2e4).emitWithAck("WAIT_FOR_BATCH", {
1239
+ version: "v2",
1240
+ batchFriendlyId: message.batchFriendlyId,
1241
+ runFriendlyIds: message.runFriendlyIds,
1242
+ attemptFriendlyId: this.attemptFriendlyId
1263
1243
  });
1264
- if (!waitForBatch.success) {
1265
- logger.error("Failed to wait for batch with backoff", {
1266
- cause: waitForBatch.cause,
1267
- error: waitForBatch.error
1268
- });
1269
- this.#emitUnrecoverableError(
1270
- "WaitForBatchFailed",
1271
- `${waitForBatch.cause}: ${waitForBatch.error}`
1272
- );
1273
- return;
1274
- }
1275
- const { willCheckpointAndRestore } = waitForBatch.result;
1276
- await this.#prepareForWait("WAIT_FOR_BATCH", willCheckpointAndRestore);
1277
- if (willCheckpointAndRestore) {
1278
- if (!this.waitForBatchReplay) {
1279
- this.waitForBatchReplay = {
1280
- message,
1281
- attempt: 1,
1282
- idempotencyKey: randomUUID()
1283
- };
1284
- } else {
1285
- if (replayIdempotencyKey && replayIdempotencyKey !== this.waitForBatchReplay.idempotencyKey) {
1286
- logger.error(
1287
- "wait for task handler called with mismatched idempotency key, won't overwrite replay request"
1288
- );
1289
- return;
1290
- }
1291
- this.waitForBatchReplay.attempt++;
1244
+ });
1245
+ if (!waitForBatch.success) {
1246
+ logger.error("Failed to wait for batch with backoff", {
1247
+ cause: waitForBatch.cause,
1248
+ error: waitForBatch.error
1249
+ });
1250
+ this.#emitUnrecoverableError(
1251
+ "WaitForBatchFailed",
1252
+ `${waitForBatch.cause}: ${waitForBatch.error}`
1253
+ );
1254
+ return;
1255
+ }
1256
+ const { willCheckpointAndRestore } = waitForBatch.result;
1257
+ await this.#prepareForWait("WAIT_FOR_BATCH", willCheckpointAndRestore);
1258
+ if (willCheckpointAndRestore) {
1259
+ if (!this.waitForBatchReplay) {
1260
+ this.waitForBatchReplay = {
1261
+ message,
1262
+ attempt: 1,
1263
+ idempotencyKey: randomUUID()
1264
+ };
1265
+ } else {
1266
+ if (replayIdempotencyKey && replayIdempotencyKey !== this.waitForBatchReplay.idempotencyKey) {
1267
+ logger.error(
1268
+ "wait for task handler called with mismatched idempotency key, won't overwrite replay request"
1269
+ );
1270
+ return;
1292
1271
  }
1272
+ this.waitForBatchReplay.attempt++;
1293
1273
  }
1294
- };
1274
+ }
1295
1275
  }
1296
1276
  // MARK: WORKER CREATION
1297
1277
  #createBackgroundWorker() {
1298
- const workerId = randomUUID();
1299
- logger.log("Creating background worker", { workerId });
1300
1278
  const backgroundWorker = new ProdBackgroundWorker("worker.js", {
1301
1279
  projectConfig: __PROJECT_CONFIG__,
1302
1280
  env: {
@@ -1308,27 +1286,18 @@ var ProdWorker = class {
1308
1286
  contentHash: this.contentHash
1309
1287
  });
1310
1288
  backgroundWorker.onTaskHeartbeat.attach((attemptFriendlyId) => {
1311
- logger.log("onTaskHeartbeat", {
1312
- workerId,
1313
- attemptFriendlyId
1314
- });
1289
+ logger.log("onTaskHeartbeat", { attemptFriendlyId });
1315
1290
  this.#coordinatorSocket.socket.volatile.emit("TASK_HEARTBEAT", {
1316
1291
  version: "v1",
1317
1292
  attemptFriendlyId
1318
1293
  });
1319
1294
  });
1320
1295
  backgroundWorker.onTaskRunHeartbeat.attach((runId) => {
1321
- logger.log("onTaskRunHeartbeat", {
1322
- workerId,
1323
- runId
1324
- });
1296
+ logger.log("onTaskRunHeartbeat", { runId });
1325
1297
  this.#coordinatorSocket.socket.volatile.emit("TASK_RUN_HEARTBEAT", { version: "v1", runId });
1326
1298
  });
1327
1299
  backgroundWorker.onCreateTaskRunAttempt.attach(async (message) => {
1328
- logger.log("onCreateTaskRunAttempt()", {
1329
- workerId,
1330
- message
1331
- });
1300
+ logger.log("onCreateTaskRunAttempt()", { message });
1332
1301
  const createAttempt = await defaultBackoff.execute(async ({ retry }) => {
1333
1302
  logger.log("Create task run attempt with backoff", { retry });
1334
1303
  return await this.#coordinatorSocket.socket.timeout(15e3).emitWithAck("CREATE_TASK_RUN_ATTEMPT", {
@@ -1357,7 +1326,6 @@ var ProdWorker = class {
1357
1326
  });
1358
1327
  backgroundWorker.attemptCreatedNotification.attach((message) => {
1359
1328
  logger.log("attemptCreatedNotification", {
1360
- workerId,
1361
1329
  success: message.success,
1362
1330
  ...message.success ? {
1363
1331
  attempt: message.execution.attempt,
@@ -1372,20 +1340,9 @@ var ProdWorker = class {
1372
1340
  return;
1373
1341
  }
1374
1342
  this.attemptFriendlyId = message.execution.attempt.id;
1375
- this.attemptNumber = message.execution.attempt.number;
1376
1343
  });
1377
1344
  backgroundWorker.onWaitForDuration.attach(async (message) => {
1378
- logger.log("onWaitForDuration", {
1379
- workerId,
1380
- ...message,
1381
- drift: Date.now() - message.now
1382
- });
1383
- if (this.nextResumeAfter) {
1384
- logger.error("Already waiting for resume, skipping wait for duration", {
1385
- nextResumeAfter: this.nextResumeAfter
1386
- });
1387
- return;
1388
- }
1345
+ logger.log("onWaitForDuration", { ...message, drift: Date.now() - message.now });
1389
1346
  noResume: {
1390
1347
  const { ms, waitThresholdInMs } = message;
1391
1348
  const internalTimeout = unboundedTimeout(ms, "internal");
@@ -1423,15 +1380,6 @@ var ProdWorker = class {
1423
1380
  }
1424
1381
  await this.#prepareForWait("WAIT_FOR_DURATION", willCheckpointAndRestore);
1425
1382
  await Promise.race([internalTimeout, checkpointSafeInternalTimeout]);
1426
- const idempotencyKey = randomUUID();
1427
- this.durationResumeFallback = { idempotencyKey };
1428
- try {
1429
- await this.restoreNotification.waitFor(5e3);
1430
- } catch (error) {
1431
- logger.error("Did not receive restore notification in time", {
1432
- error
1433
- });
1434
- }
1435
1383
  try {
1436
1384
  const { checkpointCanceled } = await this.#coordinatorSocket.socket.timeout(15e3).emitWithAck("CANCEL_CHECKPOINT", {
1437
1385
  version: "v2",
@@ -1442,6 +1390,8 @@ var ProdWorker = class {
1442
1390
  break noResume;
1443
1391
  }
1444
1392
  logger.log("Waiting for external duration resume as we may have been restored");
1393
+ const idempotencyKey = randomUUID();
1394
+ this.durationResumeFallback = { idempotencyKey };
1445
1395
  setTimeout(() => {
1446
1396
  if (!this.durationResumeFallback) {
1447
1397
  logger.error("Already resumed after duration, skipping fallback");
@@ -1455,32 +1405,19 @@ var ProdWorker = class {
1455
1405
  this.#resumeAfterDuration();
1456
1406
  }, 15e3);
1457
1407
  } catch (error) {
1458
- logger.debug("Checkpoint cancellation timed out", {
1459
- workerId,
1460
- message,
1461
- error
1462
- });
1408
+ logger.debug("Checkpoint cancellation timed out", { error });
1409
+ break noResume;
1463
1410
  }
1464
1411
  return;
1465
1412
  }
1466
1413
  this.#resumeAfterDuration();
1467
1414
  });
1468
- backgroundWorker.onWaitForTask.attach(this.#waitForTaskHandlerFactory(workerId).bind(this));
1469
- backgroundWorker.onWaitForBatch.attach(this.#waitForBatchHandlerFactory(workerId).bind(this));
1415
+ backgroundWorker.onWaitForTask.attach(this.#waitForTaskHandler.bind(this));
1416
+ backgroundWorker.onWaitForBatch.attach(this.#waitForBatchHandler.bind(this));
1470
1417
  return backgroundWorker;
1471
1418
  }
1472
1419
  async #prepareForWait(reason, willCheckpointAndRestore) {
1473
1420
  logger.log(`prepare for ${reason}`, { willCheckpointAndRestore });
1474
- if (this.nextResumeAfter) {
1475
- logger.error("Already waiting for resume, skipping prepare for wait", {
1476
- nextResumeAfter: this.nextResumeAfter,
1477
- params: {
1478
- reason,
1479
- willCheckpointAndRestore
1480
- }
1481
- });
1482
- return;
1483
- }
1484
1421
  if (!willCheckpointAndRestore) {
1485
1422
  return;
1486
1423
  }
@@ -1490,9 +1427,12 @@ var ProdWorker = class {
1490
1427
  await this.#prepareForCheckpoint();
1491
1428
  }
1492
1429
  // MARK: RETRY PREP
1493
- async #prepareForRetry(shouldExit, exitCode) {
1494
- logger.log("prepare for retry", { shouldExit, exitCode });
1430
+ async #prepareForRetry(willCheckpointAndRestore, shouldExit, exitCode) {
1431
+ logger.log("prepare for retry", { willCheckpointAndRestore, shouldExit, exitCode });
1495
1432
  if (shouldExit) {
1433
+ if (willCheckpointAndRestore) {
1434
+ logger.error("WARNING: Will checkpoint but also requested exit. This won't end well.");
1435
+ }
1496
1436
  await this.#exitGracefully(false, exitCode);
1497
1437
  return;
1498
1438
  }
@@ -1500,7 +1440,11 @@ var ProdWorker = class {
1500
1440
  this.waitForPostStart = false;
1501
1441
  this.executing = false;
1502
1442
  this.attemptFriendlyId = void 0;
1503
- this.attemptNumber = void 0;
1443
+ if (!willCheckpointAndRestore) {
1444
+ return;
1445
+ }
1446
+ this.waitForPostStart = true;
1447
+ await this.#prepareForCheckpoint(false);
1504
1448
  }
1505
1449
  // MARK: CHECKPOINT PREP
1506
1450
  async #prepareForCheckpoint(flush = true) {
@@ -1528,7 +1472,6 @@ var ProdWorker = class {
1528
1472
  this.paused = false;
1529
1473
  this.nextResumeAfter = void 0;
1530
1474
  this.waitForPostStart = false;
1531
- this.durationResumeFallback = void 0;
1532
1475
  this.#backgroundWorker.waitCompletedNotification();
1533
1476
  }
1534
1477
  async #readyForLazyAttempt() {
@@ -1593,7 +1536,7 @@ var ProdWorker = class {
1593
1536
  const taskRunCompleted = await defaultBackoff.execute(async ({ retry }) => {
1594
1537
  logger.log("Submit attempt completion with backoff", { retry });
1595
1538
  return await this.#coordinatorSocket.socket.timeout(2e4).emitWithAck("TASK_RUN_COMPLETED", {
1596
- version: "v2",
1539
+ version: "v1",
1597
1540
  execution,
1598
1541
  completion
1599
1542
  });
@@ -1609,9 +1552,26 @@ var ProdWorker = class {
1609
1552
  const { willCheckpointAndRestore, shouldExit } = taskRunCompleted.result;
1610
1553
  logger.log("completion acknowledged", { willCheckpointAndRestore, shouldExit });
1611
1554
  const exitCode = !completion.ok && completion.error.type === "INTERNAL_ERROR" && completion.error.code === TaskRunErrorCodes2.TASK_PROCESS_EXITED_WITH_NON_ZERO_CODE ? EXIT_CODE_CHILD_NONZERO : 0;
1612
- await this.#prepareForRetry(shouldExit, exitCode);
1555
+ await this.#prepareForRetry(willCheckpointAndRestore, shouldExit, exitCode);
1613
1556
  if (willCheckpointAndRestore) {
1614
- logger.error("This worker should never be checkpointed between attempts. This is a bug.");
1557
+ if (!this.submitAttemptCompletionReplay) {
1558
+ this.submitAttemptCompletionReplay = {
1559
+ message: {
1560
+ execution,
1561
+ completion
1562
+ },
1563
+ attempt: 1,
1564
+ idempotencyKey: randomUUID()
1565
+ };
1566
+ } else {
1567
+ if (replayIdempotencyKey && replayIdempotencyKey !== this.submitAttemptCompletionReplay.idempotencyKey) {
1568
+ logger.error(
1569
+ "attempt completion handler called with mismatched idempotency key, won't overwrite replay request"
1570
+ );
1571
+ return;
1572
+ }
1573
+ this.submitAttemptCompletionReplay.attempt++;
1574
+ }
1615
1575
  }
1616
1576
  }
1617
1577
  #returnValidatedExtraHeaders(headers) {
@@ -1637,9 +1597,6 @@ var ProdWorker = class {
1637
1597
  if (this.attemptFriendlyId) {
1638
1598
  extraHeaders["x-trigger-attempt-friendly-id"] = this.attemptFriendlyId;
1639
1599
  }
1640
- if (this.attemptNumber !== void 0) {
1641
- extraHeaders["x-trigger-attempt-number"] = String(this.attemptNumber);
1642
- }
1643
1600
  logger.log(`connecting to coordinator: ${host}:${COORDINATOR_PORT}`);
1644
1601
  logger.debug(`connecting with extra headers`, { extraHeaders });
1645
1602
  const coordinatorConnection = new ZodSocketConnection({
@@ -1711,13 +1668,31 @@ var ProdWorker = class {
1711
1668
  });
1712
1669
  return;
1713
1670
  }
1671
+ this.durationResumeFallback = void 0;
1714
1672
  this.#resumeAfterDuration();
1715
1673
  },
1716
- EXECUTE_TASK_RUN: async () => {
1717
- this.#failRun(
1718
- this.runId,
1719
- "Received deprecated EXECUTE_TASK_RUN message. Please contact us if you see this error."
1720
- );
1674
+ // Deprecated: This will never get called as this worker supports lazy attempts. It's only here for a quick view of the flow old workers use.
1675
+ EXECUTE_TASK_RUN: async ({ executionPayload }) => {
1676
+ if (this.executing) {
1677
+ logger.error("dropping execute request, already executing");
1678
+ return;
1679
+ }
1680
+ if (this.completed.has(executionPayload.execution.attempt.id)) {
1681
+ logger.error("dropping execute request, already completed");
1682
+ return;
1683
+ }
1684
+ this.executing = true;
1685
+ this.attemptFriendlyId = executionPayload.execution.attempt.id;
1686
+ const completion = await this.#backgroundWorker.executeTaskRun(executionPayload);
1687
+ logger.log("completed", completion);
1688
+ this.completed.add(executionPayload.execution.attempt.id);
1689
+ const { willCheckpointAndRestore, shouldExit } = await this.#coordinatorSocket.socket.emitWithAck("TASK_RUN_COMPLETED", {
1690
+ version: "v1",
1691
+ execution: executionPayload.execution,
1692
+ completion
1693
+ });
1694
+ logger.log("completion acknowledged", { willCheckpointAndRestore, shouldExit });
1695
+ await this.#prepareForRetry(willCheckpointAndRestore, shouldExit);
1721
1696
  },
1722
1697
  EXECUTE_TASK_RUN_LAZY_ATTEMPT: async (message) => {
1723
1698
  this.readyForLazyAttemptReplay = void 0;
@@ -1765,6 +1740,7 @@ var ProdWorker = class {
1765
1740
  logger.error("Received READY_FOR_RETRY but no completions yet. This is a bug.");
1766
1741
  return;
1767
1742
  }
1743
+ this.submitAttemptCompletionReplay = void 0;
1768
1744
  await this.#readyForLazyAttempt();
1769
1745
  }
1770
1746
  },
@@ -1774,11 +1750,7 @@ var ProdWorker = class {
1774
1750
  status: this.#status,
1775
1751
  connectionCount: ++this.connectionCount
1776
1752
  });
1777
- socket.emit("SET_STATE", {
1778
- version: "v1",
1779
- attemptFriendlyId: this.attemptFriendlyId,
1780
- attemptNumber: this.attemptNumber ? String(this.attemptNumber) : void 0
1781
- });
1753
+ socket.emit("SET_STATE", { version: "v1", attemptFriendlyId: this.attemptFriendlyId });
1782
1754
  try {
1783
1755
  if (this.waitForPostStart) {
1784
1756
  logger2.log("skip connection handler, waiting for post start hook");
@@ -1794,25 +1766,16 @@ var ProdWorker = class {
1794
1766
  return;
1795
1767
  }
1796
1768
  if (!this.attemptFriendlyId) {
1797
- logger2.error("Missing attempt friendly ID", { status: this.#status });
1769
+ logger2.error("Missing friendly ID", { status: this.#status });
1798
1770
  this.#emitUnrecoverableError(
1799
1771
  "NoAttemptId",
1800
1772
  "Attempt ID not set while resuming from paused state"
1801
1773
  );
1802
1774
  return;
1803
1775
  }
1804
- if (!this.attemptNumber) {
1805
- logger2.error("Missing attempt number", { status: this.#status });
1806
- this.#emitUnrecoverableError(
1807
- "NoAttemptNumber",
1808
- "Attempt number not set while resuming from paused state"
1809
- );
1810
- return;
1811
- }
1812
1776
  socket.emit("READY_FOR_RESUME", {
1813
- version: "v2",
1777
+ version: "v1",
1814
1778
  attemptFriendlyId: this.attemptFriendlyId,
1815
- attemptNumber: this.attemptNumber,
1816
1779
  type: this.nextResumeAfter
1817
1780
  });
1818
1781
  return;
@@ -1949,7 +1912,7 @@ var ProdWorker = class {
1949
1912
  }
1950
1913
  try {
1951
1914
  await backoff.wait(attempt + 1);
1952
- await this.#waitForTaskHandlerFactory("replay")(message, idempotencyKey);
1915
+ await this.#waitForTaskHandler(message);
1953
1916
  } catch (error) {
1954
1917
  if (error instanceof ExponentialBackoff.RetryLimitExceeded) {
1955
1918
  logger.error("wait for task replay retry limit exceeded", { error });
@@ -1981,7 +1944,7 @@ var ProdWorker = class {
1981
1944
  }
1982
1945
  try {
1983
1946
  await backoff.wait(attempt + 1);
1984
- await this.#waitForBatchHandlerFactory("replay")(message, idempotencyKey);
1947
+ await this.#waitForBatchHandler(message);
1985
1948
  } catch (error) {
1986
1949
  if (error instanceof ExponentialBackoff.RetryLimitExceeded) {
1987
1950
  logger.error("wait for batch replay retry limit exceeded", { error });
@@ -1991,6 +1954,38 @@ var ProdWorker = class {
1991
1954
  }
1992
1955
  return;
1993
1956
  }
1957
+ if (this.submitAttemptCompletionReplay) {
1958
+ logger.log("replaying attempt completion", {
1959
+ ...this.submitAttemptCompletionReplay,
1960
+ cancellationDelay: replayCancellationDelay
1961
+ });
1962
+ const { idempotencyKey, message, attempt } = this.submitAttemptCompletionReplay;
1963
+ await timeout2(replayCancellationDelay);
1964
+ if (!this.submitAttemptCompletionReplay) {
1965
+ logger.error("attempt completion replay cancelled, discarding", {
1966
+ originalMessage: { idempotencyKey, message, attempt }
1967
+ });
1968
+ return;
1969
+ }
1970
+ if (idempotencyKey !== this.submitAttemptCompletionReplay.idempotencyKey) {
1971
+ logger.error("attempt completion replay idempotency key mismatch, discarding", {
1972
+ originalMessage: { idempotencyKey, message, attempt },
1973
+ newMessage: this.submitAttemptCompletionReplay
1974
+ });
1975
+ return;
1976
+ }
1977
+ try {
1978
+ await backoff.wait(attempt + 1);
1979
+ await this.#submitAttemptCompletion(message.execution, message.completion, idempotencyKey);
1980
+ } catch (error) {
1981
+ if (error instanceof ExponentialBackoff.RetryLimitExceeded) {
1982
+ logger.error("attempt completion replay retry limit exceeded", { error });
1983
+ } else {
1984
+ logger.error("attempt completion replay error", { error });
1985
+ }
1986
+ }
1987
+ return;
1988
+ }
1994
1989
  }
1995
1990
  // MARK: HTTP SERVER
1996
1991
  #createHttpServer() {
@@ -2053,7 +2048,6 @@ var ProdWorker = class {
2053
2048
  }
2054
2049
  case "restore": {
2055
2050
  await this.#reconnectAfterPostStart();
2056
- this.restoreNotification.post();
2057
2051
  break;
2058
2052
  }
2059
2053
  default: {
@@ -2134,7 +2128,6 @@ var ProdWorker = class {
2134
2128
  nextResumeAfter: this.nextResumeAfter,
2135
2129
  waitForPostStart: this.waitForPostStart,
2136
2130
  attemptFriendlyId: this.attemptFriendlyId,
2137
- attemptNumber: this.attemptNumber,
2138
2131
  waitForTaskReplay: this.waitForTaskReplay,
2139
2132
  waitForBatchReplay: this.waitForBatchReplay
2140
2133
  };
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "3.0.0-beta.53";
2
+ var version = "3.0.0-beta.54";
3
3
 
4
4
  // src/workers/prod/worker-setup.ts
5
5
  import { taskCatalog } from "@trigger.dev/core/v3";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trigger.dev",
3
- "version": "3.0.0-beta.53",
3
+ "version": "3.0.0-beta.54",
4
4
  "description": "A Command-Line Interface for Trigger.dev (v3) projects",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -53,8 +53,8 @@
53
53
  "typescript": "^5.3.3",
54
54
  "vitest": "^1.6.0",
55
55
  "xdg-app-paths": "^8.3.0",
56
- "@trigger.dev/core-apps": "3.0.0-beta.53",
57
- "@trigger.dev/tsconfig": "0.0.0"
56
+ "@trigger.dev/tsconfig": "0.0.0",
57
+ "@trigger.dev/core-apps": "3.0.0-beta.54"
58
58
  },
59
59
  "dependencies": {
60
60
  "@anatine/esbuild-decorators": "^0.2.19",
@@ -72,7 +72,7 @@
72
72
  "@opentelemetry/sdk-trace-base": "^1.22.0",
73
73
  "@opentelemetry/sdk-trace-node": "^1.22.0",
74
74
  "@opentelemetry/semantic-conventions": "^1.22.0",
75
- "@trigger.dev/core": "3.0.0-beta.53",
75
+ "@trigger.dev/core": "3.0.0-beta.54",
76
76
  "@types/degit": "^2.8.3",
77
77
  "chalk": "^5.2.0",
78
78
  "chokidar": "^3.5.3",