@supergrowthai/tq 1.0.7 → 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,13 +43,14 @@ 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";
50
50
  import { Actions } from "./core/Actions.mjs";
51
51
  import { AsyncActions } from "./core/async/AsyncActions.mjs";
52
52
  import moment from "moment";
53
+ import * as os from "os";
53
54
  import { AsyncTaskManager } from "./core/async/AsyncTaskManager.mjs";
54
55
  class LockManager {
55
56
  constructor(cacheProvider, options) {
@@ -167,10 +168,19 @@ class TaskStore {
167
168
  await this.databaseAdapter.markTasksAsExecuted(tasks);
168
169
  }
169
170
  /**
170
- * 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
171
173
  */
172
174
  async markTasksAsFailed(tasks) {
173
- 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);
174
184
  }
175
185
  /**
176
186
  * Marks tasks as successful/completed
@@ -182,8 +192,9 @@ class TaskStore {
182
192
  * Marks tasks as ignored with proper task context
183
193
  */
184
194
  async markTasksAsIgnored(tasks) {
185
- const updatedTasks = tasks.map((task) => ({
195
+ const tasksWithStatus = tasks.map((task) => ({
186
196
  ...task,
197
+ status: "ignored",
187
198
  execution_stats: {
188
199
  ...task.execution_stats || {},
189
200
  error: "No executor found for task type",
@@ -191,7 +202,7 @@ class TaskStore {
191
202
  ignored_at: /* @__PURE__ */ new Date()
192
203
  }
193
204
  }));
194
- await this.databaseAdapter.markTasksAsIgnored(updatedTasks);
205
+ await this.databaseAdapter.upsertTasks(tasksWithStatus);
195
206
  }
196
207
  /**
197
208
  * Updates multiple tasks with specific updates
@@ -220,19 +231,11 @@ class TaskStore {
220
231
  await this.databaseAdapter.cleanupTasks(twoDaysAgo, now);
221
232
  }
222
233
  /**
223
- * 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
224
236
  */
225
237
  async updateTasksForRetry(tasks) {
226
- const updates = tasks.map((task) => ({
227
- id: task.id,
228
- updates: {
229
- execute_at: task.execute_at,
230
- status: task.status,
231
- execution_stats: task.execution_stats,
232
- updated_at: /* @__PURE__ */ new Date()
233
- }
234
- }));
235
- await this.databaseAdapter.updateTasks(updates);
238
+ await this.databaseAdapter.upsertTasks(tasks);
236
239
  }
237
240
  }
238
241
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
@@ -953,7 +956,7 @@ class TaskHandler {
953
956
  this.queueStats = /* @__PURE__ */ new Map();
954
957
  this.logger = new Logger("TaskHandler", LogLevel.INFO);
955
958
  this.config = config || {};
956
- this.workerId = `${(void 0)()}-${process.pid}-${Date.now()}`;
959
+ this.workerId = `${os.hostname()}-${process.pid}-${Date.now()}`;
957
960
  this.workerStartedAt = /* @__PURE__ */ new Date();
958
961
  this.taskStore = new TaskStore(databaseAdapter);
959
962
  this.taskRunner = new TaskRunner(
@@ -1176,6 +1179,7 @@ class TaskHandler {
1176
1179
  }
1177
1180
  await this.postProcessTasks({ failedTasks, newTasks, successTasks }).catch((err) => {
1178
1181
  this.logger.error("Failed to postProcessTasks", err);
1182
+ throw err;
1179
1183
  });
1180
1184
  if (!this.queueStats.has(streamName)) {
1181
1185
  this.queueStats.set(streamName, {
@@ -1231,7 +1235,7 @@ class TaskHandler {
1231
1235
  buildWorkerInfo() {
1232
1236
  return {
1233
1237
  worker_id: this.workerId,
1234
- hostname: (void 0)(),
1238
+ hostname: os.hostname(),
1235
1239
  pid: process.pid,
1236
1240
  started_at: this.workerStartedAt,
1237
1241
  enabled_queues: this.enabledQueues
@@ -1328,6 +1332,28 @@ class TaskHandler {
1328
1332
  }
1329
1333
  const matureTasks = await this.taskStore.getMatureTasks(Date.now());
1330
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
+ }
1331
1357
  await this.addTasks(matureTasks);
1332
1358
  } catch (error) {
1333
1359
  this.logger.error(`Error processing tasks: ${error}`);