@detiq/crawler 1.1.18 → 1.1.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@detiq/crawler",
3
- "version": "1.1.18",
3
+ "version": "1.1.19",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public",
package/src/job-queue.ts CHANGED
@@ -240,8 +240,25 @@ export async function claimNextQueuedJob(): Promise<ClaimedJob | null> {
240
240
 
241
241
  /** Requeues RUNNING jobs whose heartbeat has gone stale — the worker that claimed them
242
242
  * died (crash, restart, OOM) without ever marking them DONE/FAILED. Idempotent and
243
- * safe to run from every worker process; only affects rows past the timeout. */
243
+ * safe to run from every worker process; only affects rows past the timeout.
244
+ * API-in-process job types (GENERATE_SCRIPT etc.) are failed directly — requeueing them
245
+ * would cause the worker to claim and fail them with a confusing "claimed by worker" error. */
244
246
  export async function requeueStaleRunningJobs(): Promise<void> {
247
+ // Directly fail stale API-in-process jobs — worker cannot process these types.
248
+ const failedRows = await prismaAdmin.$queryRaw<Array<{ id: string }>>`
249
+ UPDATE "PlatformJob"
250
+ SET status = 'FAILED',
251
+ "finishedAt" = NOW(),
252
+ error = 'API process was restarted while this job was running — please retry from the UI.'
253
+ WHERE status = 'RUNNING'
254
+ AND type IN ('GENERATE_SCRIPT', 'GENERATE_DATA', 'GENERATE_TESTS', 'GENERATE_TEST_PLAN')
255
+ AND COALESCE("heartbeatAt", "startedAt") < NOW() - (${STALE_JOB_TIMEOUT_MINUTES} * interval '1 minute')
256
+ RETURNING id
257
+ `;
258
+ if (failedRows.length > 0) {
259
+ logger.warn({ jobIds: failedRows.map((r: any) => r.id), staleTimeoutMinutes: STALE_JOB_TIMEOUT_MINUTES }, '[job-worker] failed stale API-in-process job(s) — API restarted while running');
260
+ }
261
+
245
262
  const rows = await prismaAdmin.$queryRaw<Array<{ id: string }>>`
246
263
  UPDATE "PlatformJob"
247
264
  SET status = 'QUEUED',
@@ -253,6 +270,7 @@ export async function requeueStaleRunningJobs(): Promise<void> {
253
270
  true
254
271
  )
255
272
  WHERE status = 'RUNNING'
273
+ AND type NOT IN ('GENERATE_SCRIPT', 'GENERATE_DATA', 'GENERATE_TESTS', 'GENERATE_TEST_PLAN')
256
274
  AND COALESCE("heartbeatAt", "startedAt") < NOW() - (${STALE_JOB_TIMEOUT_MINUTES} * interval '1 minute')
257
275
  RETURNING id
258
276
  `;
@@ -2510,7 +2528,7 @@ jobDispatchTable = {
2510
2528
  BATCH_GENERATE_ALIGNED: processBatchGenerateAlignedJob,
2511
2529
  CREATE_PR: processCreatePRJob,
2512
2530
  NEW_PAGES_PIPELINE: processNewPagesPipelineJob,
2513
- // GENERATE_TESTS is processed in-process by the API (never QUEUED).
2531
+ // The following job types are processed in-process by the API (never QUEUED).
2514
2532
  // If the worker claims one, the API crashed after creating it — mark failed so it's visible.
2515
2533
  GENERATE_TESTS: async (jobId: string, _config: any) => {
2516
2534
  logger.error({ jobId }, '[job-worker] GENERATE_TESTS claimed by worker — API did not process it in-process');
@@ -2519,6 +2537,27 @@ jobDispatchTable = {
2519
2537
  data: { status: 'FAILED', error: 'Test generation was not completed by the API — please retry from the UI.', finishedAt: new Date() },
2520
2538
  }).catch(() => {});
2521
2539
  },
2540
+ GENERATE_DATA: async (jobId: string, _config: any) => {
2541
+ logger.error({ jobId }, '[job-worker] GENERATE_DATA claimed by worker — API did not process it in-process');
2542
+ await prismaAdmin.platformJob.update({
2543
+ where: { id: jobId },
2544
+ data: { status: 'FAILED', error: 'Data generation was not completed by the API — please retry from the UI.', finishedAt: new Date() },
2545
+ }).catch(() => {});
2546
+ },
2547
+ GENERATE_SCRIPT: async (jobId: string, _config: any) => {
2548
+ logger.error({ jobId }, '[job-worker] GENERATE_SCRIPT claimed by worker — API did not process it in-process');
2549
+ await prismaAdmin.platformJob.update({
2550
+ where: { id: jobId },
2551
+ data: { status: 'FAILED', error: 'Script generation was not completed by the API — please retry from the UI.', finishedAt: new Date() },
2552
+ }).catch(() => {});
2553
+ },
2554
+ GENERATE_TEST_PLAN: async (jobId: string, _config: any) => {
2555
+ logger.error({ jobId }, '[job-worker] GENERATE_TEST_PLAN claimed by worker — API did not process it in-process');
2556
+ await prismaAdmin.platformJob.update({
2557
+ where: { id: jobId },
2558
+ data: { status: 'FAILED', error: 'Test plan generation was not completed by the API — please retry from the UI.', finishedAt: new Date() },
2559
+ }).catch(() => {});
2560
+ },
2522
2561
  };
2523
2562
 
2524
2563
  async function processRepoScanJob(jobId: string, config: any) {