@supergrowthai/tq 1.0.12 → 1.0.13

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/index.cjs CHANGED
@@ -1122,7 +1122,6 @@ class TaskHandler {
1122
1122
  }
1123
1123
  async addTasks(tasks) {
1124
1124
  tasks = tasks.map((t) => this.validateLogContext(t));
1125
- const enrichedTasks = [];
1126
1125
  const diffedItems = tasks.reduce(
1127
1126
  (acc, { force_store, ...task }) => {
1128
1127
  const currentTime = /* @__PURE__ */ new Date();
@@ -1157,8 +1156,16 @@ class TaskHandler {
1157
1156
  const partitionKey = executor?.getPartitionKey?.(task);
1158
1157
  return { ...id, ...task, ...partitionKey ? { partition_key: partitionKey } : {} };
1159
1158
  });
1159
+ if (this.entityProjectionProvider) {
1160
+ try {
1161
+ const includePayload = this.config.entityProjectionConfig?.includePayload;
1162
+ const entityProjections = queueTasks.filter((t) => t.entity).map((t) => core_async_AsyncActions.buildProjection(t, "scheduled", { includePayload })).filter((p) => p !== null);
1163
+ await core_async_AsyncActions.syncProjections(entityProjections, this.entityProjectionProvider, this.logger);
1164
+ } catch (err) {
1165
+ this.logger.error(`[TQ] Entity projection failed (non-fatal): ${err}`);
1166
+ }
1167
+ }
1160
1168
  await this.messageQueue.addMessages(queue, queueTasks);
1161
- enrichedTasks.push(...queueTasks);
1162
1169
  if (this.lifecycleProvider?.onTaskScheduled) {
1163
1170
  for (const task of queueTasks) {
1164
1171
  this.emitLifecycleEvent(
@@ -1176,6 +1183,15 @@ class TaskHandler {
1176
1183
  return { ...id, ...task, status: "processing", processing_started_at: /* @__PURE__ */ new Date() };
1177
1184
  });
1178
1185
  await this.taskStore.addTasksToScheduled(queueTasks);
1186
+ if (this.entityProjectionProvider) {
1187
+ try {
1188
+ const includePayload = this.config.entityProjectionConfig?.includePayload;
1189
+ const entityProjections = queueTasks.filter((t) => t.entity).map((t) => core_async_AsyncActions.buildProjection(t, "scheduled", { includePayload })).filter((p) => p !== null);
1190
+ await core_async_AsyncActions.syncProjections(entityProjections, this.entityProjectionProvider, this.logger);
1191
+ } catch (err) {
1192
+ this.logger.error(`[TQ] Entity projection failed (non-fatal): ${err}`);
1193
+ }
1194
+ }
1179
1195
  const mqTasks = queueTasks.map((t) => ({ ...t, status: "scheduled" }));
1180
1196
  try {
1181
1197
  await this.messageQueue.addMessages(queue, mqTasks);
@@ -1191,7 +1207,6 @@ class TaskHandler {
1191
1207
  }
1192
1208
  throw mqError;
1193
1209
  }
1194
- enrichedTasks.push(...queueTasks);
1195
1210
  if (this.lifecycleProvider?.onTaskScheduled) {
1196
1211
  for (const task of queueTasks) {
1197
1212
  this.emitLifecycleEvent(
@@ -1211,7 +1226,15 @@ class TaskHandler {
1211
1226
  return { ...id, ...task };
1212
1227
  });
1213
1228
  await this.taskStore.addTasksToScheduled(queueTasks);
1214
- enrichedTasks.push(...queueTasks);
1229
+ if (this.entityProjectionProvider) {
1230
+ try {
1231
+ const includePayload = this.config.entityProjectionConfig?.includePayload;
1232
+ const entityProjections = queueTasks.filter((t) => t.entity).map((t) => core_async_AsyncActions.buildProjection(t, "scheduled", { includePayload })).filter((p) => p !== null);
1233
+ await core_async_AsyncActions.syncProjections(entityProjections, this.entityProjectionProvider, this.logger);
1234
+ } catch (err) {
1235
+ this.logger.error(`[TQ] Entity projection failed (non-fatal): ${err}`);
1236
+ }
1237
+ }
1215
1238
  if (this.lifecycleProvider?.onTaskScheduled) {
1216
1239
  for (const task of queueTasks) {
1217
1240
  this.emitLifecycleEvent(
@@ -1221,15 +1244,6 @@ class TaskHandler {
1221
1244
  }
1222
1245
  }
1223
1246
  }
1224
- if (this.entityProjectionProvider) {
1225
- try {
1226
- const includePayload = this.config.entityProjectionConfig?.includePayload;
1227
- const entityProjections = enrichedTasks.filter((t) => t.entity).map((t) => core_async_AsyncActions.buildProjection(t, "scheduled", { includePayload })).filter((p) => p !== null);
1228
- await core_async_AsyncActions.syncProjections(entityProjections, this.entityProjectionProvider, this.logger);
1229
- } catch (err) {
1230
- this.logger.error(`[TQ] Entity projection failed (non-fatal): ${err}`);
1231
- }
1232
- }
1233
1247
  }
1234
1248
  // TODO(P2): Wrap retry upsert → new tasks → mark failed → mark success in a
1235
1249
  // transaction. If an intermediate step fails, tasks can be lost or re-executed
@@ -1312,7 +1326,25 @@ class TaskHandler {
1312
1326
  await this.trackDiscardedTasks(discardedTasks.length);
1313
1327
  }
1314
1328
  if (tasksToRetry.length > 0) {
1315
- await this.taskStore.updateTasksForRetry(tasksToRetry);
1329
+ const dbRetryTasks = tasksToRetry.map((t) => ({
1330
+ ...t,
1331
+ status: "processing",
1332
+ processing_started_at: /* @__PURE__ */ new Date()
1333
+ }));
1334
+ await this.taskStore.updateTasksForRetry(dbRetryTasks);
1335
+ const retryByQueue = /* @__PURE__ */ new Map();
1336
+ for (const task of tasksToRetry) {
1337
+ const queue = task.queue_id;
1338
+ if (!retryByQueue.has(queue)) retryByQueue.set(queue, []);
1339
+ retryByQueue.get(queue).push(task);
1340
+ }
1341
+ for (const [queue, retryQueueTasks] of retryByQueue) {
1342
+ try {
1343
+ await this.messageQueue.addMessages(queue, retryQueueTasks);
1344
+ } catch (mqErr) {
1345
+ this.logger.error(`[TQ] Failed to re-enqueue retry tasks to MQ (stale recovery will handle): ${mqErr}`);
1346
+ }
1347
+ }
1316
1348
  }
1317
1349
  if (finalFailedTasks.length > 0) {
1318
1350
  await this.taskStore.markTasksAsFailed(finalFailedTasks);