78 lines
2.5 KiB
JavaScript
78 lines
2.5 KiB
JavaScript
'use strict';
|
|
|
|
const { Worker } = require('bullmq');
|
|
const db = require('../infra/db');
|
|
const audit = require('../audit/audit');
|
|
const { connection } = require('./queue');
|
|
const { generate } = require('./generator');
|
|
const exportService = require('./export.service');
|
|
|
|
const worker = new Worker(
|
|
'profile-exports',
|
|
async (job) => {
|
|
const { jobUuid, type, params } = job.data;
|
|
await db.execute(
|
|
"UPDATE export_jobs SET status = 'processing', progress = 10, started_at = NOW(), error = NULL WHERE job_uuid = ?",
|
|
[jobUuid],
|
|
);
|
|
await job.updateProgress(10);
|
|
const file = await generate(jobUuid, type, params);
|
|
await job.updateProgress(90);
|
|
await db.execute(
|
|
`UPDATE export_jobs
|
|
SET status = 'completed', progress = 100, file_name = ?, file_path = ?,
|
|
mime_type = ?, file_size = ?, file_hash = ?, completed_at = NOW()
|
|
WHERE job_uuid = ?`,
|
|
[file.fileName, file.filePath, file.mimeType, file.fileSize, file.fileHash, jobUuid],
|
|
);
|
|
await audit.log({
|
|
userId: Number(job.data.requestedBy),
|
|
clientType: 'system',
|
|
action: 'export_completed',
|
|
module: 'exports',
|
|
targetType: 'export_job',
|
|
targetId: jobUuid,
|
|
payload: { type, fileName: file.fileName, fileSize: file.fileSize, fileHash: file.fileHash },
|
|
});
|
|
return { fileName: file.fileName, fileHash: file.fileHash };
|
|
},
|
|
{
|
|
connection: connection.duplicate(),
|
|
concurrency: 2,
|
|
limiter: { max: 10, duration: 60 * 1000 },
|
|
},
|
|
);
|
|
|
|
worker.on('failed', async (job, error) => {
|
|
if (!job) return;
|
|
await db.execute(
|
|
"UPDATE export_jobs SET status = 'failed', progress = 0, error = ?, completed_at = NOW() WHERE job_uuid = ?",
|
|
[String(error.message || error).slice(0, 1000), job.data.jobUuid],
|
|
);
|
|
await audit.log({
|
|
userId: Number(job.data.requestedBy),
|
|
clientType: 'system',
|
|
action: 'export_failed',
|
|
module: 'exports',
|
|
targetType: 'export_job',
|
|
targetId: job.data.jobUuid,
|
|
payload: { type: job.data.type, error: String(error.message || error).slice(0, 500) },
|
|
});
|
|
});
|
|
|
|
const cleanupTimer = setInterval(() => {
|
|
exportService.cleanupExpired().catch((error) => console.error('[export-worker] cleanup failed:', error.message));
|
|
}, 60 * 60 * 1000);
|
|
|
|
async function shutdown() {
|
|
clearInterval(cleanupTimer);
|
|
await worker.close();
|
|
await connection.quit();
|
|
await db.close();
|
|
}
|
|
|
|
process.on('SIGINT', shutdown);
|
|
process.on('SIGTERM', shutdown);
|
|
|
|
console.log('[export-worker] ready, concurrency=2');
|