fix: users can retriger transcription
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
import './../bootstrap';
|
||||
|
||||
import { Worker } from 'bullmq';
|
||||
import { Queue, Worker } from 'bullmq';
|
||||
|
||||
import { pruneDeadLetterJobsOlderThan } from '@cio/db/queries';
|
||||
import { pruneDeadLetterJobsOlderThan, reapStuckMediaJobs } from '@cio/db/queries';
|
||||
import {
|
||||
JOB_NAMES,
|
||||
QUEUE_NAMES,
|
||||
ZDeadLetterCleanupPayload,
|
||||
ZMediaJobReapPayload,
|
||||
ZRetentionCompactPayload,
|
||||
createRedisConnection
|
||||
} from '@cio/jobs';
|
||||
@@ -36,11 +37,56 @@ const worker = new Worker(
|
||||
return { compacted: 0 };
|
||||
}
|
||||
|
||||
if (job.name === JOB_NAMES.maintenance.mediaJobReap) {
|
||||
const data = ZMediaJobReapPayload.parse(job.data ?? {});
|
||||
const cutoffIso = new Date(Date.now() - data.staleAfterMinutes * 60 * 1_000).toISOString();
|
||||
const reaped = await reapStuckMediaJobs(cutoffIso);
|
||||
|
||||
if (reaped.length > 0) {
|
||||
log.warn('media-job-reap-done', {
|
||||
reaped: reaped.length,
|
||||
cutoffIso,
|
||||
ids: reaped.map((row) => row.id)
|
||||
});
|
||||
}
|
||||
|
||||
return { reaped: reaped.length };
|
||||
}
|
||||
|
||||
throw new Error(`Unknown maintenance job: ${job.name}`);
|
||||
},
|
||||
{ connection, concurrency: 1 }
|
||||
);
|
||||
|
||||
/**
|
||||
* BullMQ repeatable scheduler for the media-job reaper. `upsertJobScheduler`
|
||||
* is idempotent on the scheduler id, so it's safe to call on every worker
|
||||
* boot. Without this, stuck `media_job` rows would never get cleaned up.
|
||||
*/
|
||||
const MEDIA_JOB_REAP_INTERVAL_MS = 5 * 60 * 1_000;
|
||||
// BullMQ requires a dedicated connection per Worker; give the Queue its own
|
||||
// so the scheduler upsert doesn't piggyback on the worker's blocking client.
|
||||
const schedulerConnection = createRedisConnection();
|
||||
const maintenanceQueue = new Queue(QUEUE_NAMES.maintenance, { connection: schedulerConnection });
|
||||
|
||||
async function registerSchedulers(): Promise<void> {
|
||||
try {
|
||||
await maintenanceQueue.upsertJobScheduler(
|
||||
'media-job-reap-scheduler',
|
||||
{ every: MEDIA_JOB_REAP_INTERVAL_MS },
|
||||
{ name: JOB_NAMES.maintenance.mediaJobReap, data: {} }
|
||||
);
|
||||
log.info('maintenance-scheduler-registered', {
|
||||
name: JOB_NAMES.maintenance.mediaJobReap,
|
||||
everyMs: MEDIA_JOB_REAP_INTERVAL_MS
|
||||
});
|
||||
} catch (err) {
|
||||
log.error('maintenance-scheduler-register-failed', { error: errorMessage(err) });
|
||||
}
|
||||
}
|
||||
|
||||
void registerSchedulers();
|
||||
|
||||
worker.on('ready', () => log.info('maintenance-worker-ready'));
|
||||
worker.on('failed', (job, err) =>
|
||||
log.error('maintenance-job-failed', { jobName: job?.name, error: errorMessage(err) })
|
||||
@@ -50,6 +96,8 @@ worker.on('error', (err) => log.error('maintenance-worker-error', { error: error
|
||||
const shutdown = async (signal: string) => {
|
||||
log.info('maintenance-worker-shutdown', { signal });
|
||||
await worker.close();
|
||||
await maintenanceQueue.close();
|
||||
await schedulerConnection.quit();
|
||||
await connection.quit();
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user