diff --git a/server/lib/job-queue/handlers/generate-storyboard.ts b/server/lib/job-queue/handlers/generate-storyboard.ts index ec07c568c..169b5ef2d 100644 --- a/server/lib/job-queue/handlers/generate-storyboard.ts +++ b/server/lib/job-queue/handlers/generate-storyboard.ts @@ -1,10 +1,13 @@ import { Job } from 'bullmq' import { join } from 'path' +import { retryTransactionWrapper } from '@server/helpers/database-utils' import { getFFmpegCommandWrapperOptions } from '@server/helpers/ffmpeg' import { generateImageFilename, getImageSize } from '@server/helpers/image-utils' import { logger, loggerTagsFactory } from '@server/helpers/logger' +import { deleteFileAndCatch } from '@server/helpers/utils' import { CONFIG } from '@server/initializers/config' import { STORYBOARD } from '@server/initializers/constants' +import { sequelizeTypescript } from '@server/initializers/database' import { federateVideoIfNeeded } from '@server/lib/activitypub/videos' import { VideoPathManager } from '@server/lib/video-path-manager' import { StoryboardModel } from '@server/models/video/storyboard' @@ -75,25 +78,39 @@ async function processGenerateStoryboard (job: Job): Promise { const imageSize = await getImageSize(destination) - const existing = await StoryboardModel.loadByVideo(video.id) - if (existing) await existing.destroy() + await retryTransactionWrapper(() => { + return sequelizeTypescript.transaction(async transaction => { + const videoStillExists = await VideoModel.load(video.id, transaction) + if (!videoStillExists) { + logger.info('Video %s does not exist anymore, skipping storyboard generation.', payload.videoUUID, lTags) + deleteFileAndCatch(destination) + return + } - await StoryboardModel.create({ - filename, - totalHeight: imageSize.height, - totalWidth: imageSize.width, - spriteHeight: STORYBOARD.SPRITE_SIZE.height, - spriteWidth: STORYBOARD.SPRITE_SIZE.width, - spriteDuration, - videoId: video.id + const existing = await StoryboardModel.loadByVideo(video.id, transaction) + if (existing) await existing.destroy({ transaction }) + + await StoryboardModel.create({ + filename, + totalHeight: imageSize.height, + totalWidth: imageSize.width, + spriteHeight: STORYBOARD.SPRITE_SIZE.height, + spriteWidth: STORYBOARD.SPRITE_SIZE.width, + spriteDuration, + videoId: video.id + }, { transaction }) + + logger.info('Storyboard generation %s ended for video %s.', destination, video.uuid, lTags) + + if (payload.federate) { + await federateVideoIfNeeded(video, false, transaction) + } + }) }) - logger.info('Storyboard generation %s ended for video %s.', destination, video.uuid, lTags) }) - if (payload.federate) { - await federateVideoIfNeeded(video, false) - } + } finally { inputFileMutexReleaser() } diff --git a/server/models/video/storyboard.ts b/server/models/video/storyboard.ts index 65a044c98..1c3c6d850 100644 --- a/server/models/video/storyboard.ts +++ b/server/models/video/storyboard.ts @@ -59,7 +59,7 @@ export class StoryboardModel extends Model VideoModel, { foreignKey: { - allowNull: true + allowNull: false }, onDelete: 'CASCADE' })