@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/dist/job-queue.js +25 -1
- package/dist/job-queue.js.map +2 -2
- package/package.json +1 -1
- package/src/job-queue.ts +41 -2
package/package.json
CHANGED
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
|
-
//
|
|
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) {
|