diff --git a/backend/src/services/videoProcessing.js b/backend/src/services/videoProcessing.js index 25c0a31..cc91497 100644 --- a/backend/src/services/videoProcessing.js +++ b/backend/src/services/videoProcessing.js @@ -17,6 +17,43 @@ const { logger } = require('../utils/logger'); ffmpeg.setFfmpegPath(ffmpegPath); ffmpeg.setFfprobePath(ffprobePath); +let ffmpegQueueTail = Promise.resolve(); +let queuedFfmpegJobs = 0; +let ffmpegJobSequence = 0; + +async function enqueueFfmpegJob(jobName, runJob) { + const jobId = ++ffmpegJobSequence; + const queuedAhead = queuedFfmpegJobs; + + queuedFfmpegJobs++; + + logger.info( + { jobId, jobName, queuedAhead }, + 'FFmpeg job queued for single-worker execution', + ); + + const previousTail = ffmpegQueueTail.catch(() => { + // Keep the queue moving even if the previous job failed. + }); + + const jobPromise = previousTail.then(async () => { + queuedFfmpegJobs = Math.max(0, queuedFfmpegJobs - 1); + logger.info( + { jobId, jobName, queuedRemaining: queuedFfmpegJobs }, + 'FFmpeg job started', + ); + + try { + return await runJob(); + } finally { + logger.info({ jobId, jobName }, 'FFmpeg job finished'); + } + }); + + ffmpegQueueTail = jobPromise; + return jobPromise; +} + /** * Reverse a video using FFmpeg * @param {Buffer} inputBuffer - Input video buffer @@ -24,6 +61,12 @@ ffmpeg.setFfprobePath(ffprobePath); * @returns {Promise} Reversed video buffer */ async function reverseVideo(inputBuffer, filename) { + return enqueueFfmpegJob('reverseVideo', () => + reverseVideoWithoutQueue(inputBuffer, filename), + ); +} + +async function reverseVideoWithoutQueue(inputBuffer, filename) { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'video-reverse-')); const ext = path.extname(filename) || '.mp4'; const inputPath = path.join(tempDir, `input${ext}`); @@ -51,6 +94,8 @@ async function reverseVideo(inputBuffer, filename) { '23', '-c:a', 'aac', + '-threads', + '1', '-movflags', '+faststart', ])