X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Fvideo-state.ts;h=893725d85012f674b96d7274574c66c2d37d26d5;hb=e901579b00fbcd8fc0f7b45fd841636329148a34;hp=9352a67d1a9990bf54db33703c79197951555a8a;hpb=9db2330e4a32a3bb0fe821abec1b061e4edb65b5;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/video-state.ts b/server/lib/video-state.ts index 9352a67d1..893725d85 100644 --- a/server/lib/video-state.ts +++ b/server/lib/video-state.ts @@ -1,14 +1,16 @@ import { Transaction } from 'sequelize' +import { retryTransactionWrapper } from '@server/helpers/database-utils' import { logger } from '@server/helpers/logger' import { CONFIG } from '@server/initializers/config' import { sequelizeTypescript } from '@server/initializers/database' import { VideoModel } from '@server/models/video/video' import { VideoJobInfoModel } from '@server/models/video/video-job-info' -import { MVideoFullLight, MVideoUUID } from '@server/types/models' +import { MVideo, MVideoFullLight, MVideoUUID } from '@server/types/models' import { VideoState } from '@shared/models' import { federateVideoIfNeeded } from './activitypub/videos' +import { JobQueue } from './job-queue' import { Notifier } from './notifier' -import { addMoveToObjectStorageJob } from './video' +import { buildMoveToObjectStorageJob } from './video' function buildNextVideoState (currentState?: VideoState) { if (currentState === VideoState.PUBLISHED) { @@ -16,6 +18,7 @@ function buildNextVideoState (currentState?: VideoState) { } if ( + currentState !== VideoState.TO_EDIT && currentState !== VideoState.TO_TRANSCODE && currentState !== VideoState.TO_MOVE_TO_EXTERNAL_STORAGE && CONFIG.TRANSCODING.ENABLED @@ -33,67 +36,119 @@ function buildNextVideoState (currentState?: VideoState) { return VideoState.PUBLISHED } -function moveToNextState (video: MVideoUUID, isNewVideo = true) { - return sequelizeTypescript.transaction(async t => { - // Maybe the video changed in database, refresh it - const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t) - // Video does not exist anymore - if (!videoDatabase) return undefined +function moveToNextState (options: { + video: MVideoUUID + previousVideoState?: VideoState + isNewVideo?: boolean // Default true +}) { + const { video, previousVideoState, isNewVideo = true } = options + + return retryTransactionWrapper(() => { + return sequelizeTypescript.transaction(async t => { + // Maybe the video changed in database, refresh it + const videoDatabase = await VideoModel.loadFull(video.uuid, t) + // Video does not exist anymore + if (!videoDatabase) return undefined + + // Already in its final state + if (videoDatabase.state === VideoState.PUBLISHED) { + return federateVideoIfNeeded(videoDatabase, false, t) + } + + const newState = buildNextVideoState(videoDatabase.state) + + if (newState === VideoState.PUBLISHED) { + return moveToPublishedState({ video: videoDatabase, previousVideoState, isNewVideo, transaction: t }) + } + + if (newState === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE) { + return moveToExternalStorageState({ video: videoDatabase, isNewVideo, transaction: t }) + } + }) + }) +} - // Already in its final state - if (videoDatabase.state === VideoState.PUBLISHED) { - return federateVideoIfNeeded(videoDatabase, false, t) - } +async function moveToExternalStorageState (options: { + video: MVideoFullLight + isNewVideo: boolean + transaction: Transaction +}) { + const { video, isNewVideo, transaction } = options - const newState = buildNextVideoState(videoDatabase.state) + const videoJobInfo = await VideoJobInfoModel.load(video.id, transaction) + const pendingTranscode = videoJobInfo?.pendingTranscode || 0 - if (newState === VideoState.PUBLISHED) { - return moveToPublishedState(videoDatabase, isNewVideo, t) - } + // We want to wait all transcoding jobs before moving the video on an external storage + if (pendingTranscode !== 0) return false - if (newState === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE) { - return moveToExternalStorageState(videoDatabase, isNewVideo, t) - } - }) + const previousVideoState = video.state + + if (video.state !== VideoState.TO_MOVE_TO_EXTERNAL_STORAGE) { + await video.setNewState(VideoState.TO_MOVE_TO_EXTERNAL_STORAGE, isNewVideo, transaction) + } + + logger.info('Creating external storage move job for video %s.', video.uuid, { tags: [ video.uuid ] }) + + try { + await JobQueue.Instance.createJob(await buildMoveToObjectStorageJob({ video, previousVideoState, isNewVideo })) + + return true + } catch (err) { + logger.error('Cannot add move to object storage job', { err }) + + return false + } +} + +function moveToFailedTranscodingState (video: MVideo) { + if (video.state === VideoState.TRANSCODING_FAILED) return + + return video.setNewState(VideoState.TRANSCODING_FAILED, false, undefined) +} + +function moveToFailedMoveToObjectStorageState (video: MVideo) { + if (video.state === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED) return + + return video.setNewState(VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED, false, undefined) } // --------------------------------------------------------------------------- export { buildNextVideoState, + moveToExternalStorageState, + moveToFailedTranscodingState, + moveToFailedMoveToObjectStorageState, moveToNextState } // --------------------------------------------------------------------------- -async function moveToPublishedState (video: MVideoFullLight, isNewVideo: boolean, transaction: Transaction) { - logger.info('Publishing video %s.', video.uuid, { tags: [ video.uuid ] }) +async function moveToPublishedState (options: { + video: MVideoFullLight + isNewVideo: boolean + transaction: Transaction + previousVideoState?: VideoState +}) { + const { video, isNewVideo, transaction, previousVideoState } = options + const previousState = previousVideoState ?? video.state + + logger.info('Publishing video %s.', video.uuid, { isNewVideo, previousState, tags: [ video.uuid ] }) - const previousState = video.state await video.setNewState(VideoState.PUBLISHED, isNewVideo, transaction) - // If the video was not published, we consider it is a new one for other instances - // Live videos are always federated, so it's not a new video await federateVideoIfNeeded(video, isNewVideo, transaction) - if (isNewVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(video) - - if (previousState === VideoState.TO_TRANSCODE) { - Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(video) + if (previousState === VideoState.TO_EDIT) { + Notifier.Instance.notifyOfFinishedVideoStudioEdition(video) + return } -} -async function moveToExternalStorageState (video: MVideoFullLight, isNewVideo: boolean, transaction: Transaction) { - const videoJobInfo = await VideoJobInfoModel.load(video.id, transaction) - const pendingTranscode = videoJobInfo?.pendingTranscode || 0 - - // We want to wait all transcoding jobs before moving the video on an external storage - if (pendingTranscode !== 0) return - - await video.setNewState(VideoState.TO_MOVE_TO_EXTERNAL_STORAGE, isNewVideo, transaction) + if (isNewVideo) { + Notifier.Instance.notifyOnNewVideoIfNeeded(video) - logger.info('Creating external storage move job for video %s.', video.uuid, { tags: [ video.uuid ] }) - - addMoveToObjectStorageJob(video, isNewVideo) - .catch(err => logger.error('Cannot add move to object storage job', { err })) + if (previousState === VideoState.TO_TRANSCODE) { + Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(video) + } + } }