'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');