@supergrowthai/tq 1.0.8 → 1.0.9

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.mjs CHANGED
@@ -43,7 +43,7 @@ var __callDispose = (stack, error, hasError) => {
43
43
  };
44
44
  return next();
45
45
  };
46
- import { I, M, P } from "./PrismaAdapter-Z2vLslDJ.js";
46
+ import { I, M, P } from "./PrismaAdapter-BD8f3tk9.js";
47
47
  import { getEnvironmentQueueName } from "@supergrowthai/mq";
48
48
  import { L as Logger, a as LogLevel } from "./client-BAiCkZv7.js";
49
49
  import { tId } from "./utils/task-id-gen.mjs";
@@ -168,10 +168,19 @@ class TaskStore {
168
168
  await this.databaseAdapter.markTasksAsExecuted(tasks);
169
169
  }
170
170
  /**
171
- * Marks tasks as failed and increments retry count
171
+ * Marks tasks as failed uses upsert to handle store_on_failure tasks
172
+ * that were never persisted to DB
172
173
  */
173
174
  async markTasksAsFailed(tasks) {
174
- await this.databaseAdapter.markTasksAsFailed(tasks);
175
+ const tasksWithStatus = tasks.map((task) => ({
176
+ ...task,
177
+ status: "failed",
178
+ execution_stats: {
179
+ ...task.execution_stats || {},
180
+ failed_at: /* @__PURE__ */ new Date()
181
+ }
182
+ }));
183
+ await this.databaseAdapter.upsertTasks(tasksWithStatus);
175
184
  }
176
185
  /**
177
186
  * Marks tasks as successful/completed
@@ -183,8 +192,9 @@ class TaskStore {
183
192
  * Marks tasks as ignored with proper task context
184
193
  */
185
194
  async markTasksAsIgnored(tasks) {
186
- const updatedTasks = tasks.map((task) => ({
195
+ const tasksWithStatus = tasks.map((task) => ({
187
196
  ...task,
197
+ status: "ignored",
188
198
  execution_stats: {
189
199
  ...task.execution_stats || {},
190
200
  error: "No executor found for task type",
@@ -192,7 +202,7 @@ class TaskStore {
192
202
  ignored_at: /* @__PURE__ */ new Date()
193
203
  }
194
204
  }));
195
- await this.databaseAdapter.markTasksAsIgnored(updatedTasks);
205
+ await this.databaseAdapter.upsertTasks(tasksWithStatus);
196
206
  }
197
207
  /**
198
208
  * Updates multiple tasks with specific updates
@@ -221,19 +231,11 @@ class TaskStore {
221
231
  await this.databaseAdapter.cleanupTasks(twoDaysAgo, now);
222
232
  }
223
233
  /**
224
- * Updates tasks for retry with new execution time and retry count
234
+ * Updates tasks for retry uses upsert to handle store_on_failure tasks
235
+ * that were never persisted to DB
225
236
  */
226
237
  async updateTasksForRetry(tasks) {
227
- const updates = tasks.map((task) => ({
228
- id: task.id,
229
- updates: {
230
- execute_at: task.execute_at,
231
- status: task.status,
232
- execution_stats: task.execution_stats,
233
- updated_at: /* @__PURE__ */ new Date()
234
- }
235
- }));
236
- await this.databaseAdapter.updateTasks(updates);
238
+ await this.databaseAdapter.upsertTasks(tasks);
237
239
  }
238
240
  }
239
241
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
@@ -1177,6 +1179,7 @@ class TaskHandler {
1177
1179
  }
1178
1180
  await this.postProcessTasks({ failedTasks, newTasks, successTasks }).catch((err) => {
1179
1181
  this.logger.error("Failed to postProcessTasks", err);
1182
+ throw err;
1180
1183
  });
1181
1184
  if (!this.queueStats.has(streamName)) {
1182
1185
  this.queueStats.set(streamName, {
@@ -1329,6 +1332,28 @@ class TaskHandler {
1329
1332
  }
1330
1333
  const matureTasks = await this.taskStore.getMatureTasks(Date.now());
1331
1334
  this.logger.debug(`Found ${matureTasks.length} mature tasks to process`);
1335
+ if (matureTasks.length > 0) {
1336
+ try {
1337
+ const tasksWithIds = matureTasks.filter((t) => t.id);
1338
+ const dedupKeys = tasksWithIds.map((t) => `mature_dedup:${t.id}`);
1339
+ if (dedupKeys.length > 0) {
1340
+ const previousPickers = await this.cacheAdapter.mget(...dedupKeys);
1341
+ for (let i = 0; i < dedupKeys.length; i++) {
1342
+ if (previousPickers[i]) {
1343
+ const task = tasksWithIds[i];
1344
+ this.logger.warn(`DUPLICATE_MATURE_PICK: task ${task.id} (${task.type}) already picked by ${previousPickers[i]}`);
1345
+ }
1346
+ }
1347
+ const pipeline = this.cacheAdapter.pipeline();
1348
+ for (const key of dedupKeys) {
1349
+ pipeline.set(key, INSTANCE_ID, 120);
1350
+ }
1351
+ await pipeline.exec();
1352
+ }
1353
+ } catch (err) {
1354
+ this.logger.warn(`Duplicate pick detection failed (best-effort): ${err}`);
1355
+ }
1356
+ }
1332
1357
  await this.addTasks(matureTasks);
1333
1358
  } catch (error) {
1334
1359
  this.logger.error(`Error processing tasks: ${error}`);