Prevent concurrent video update

This commit is contained in:
Chocobozzz 2021-11-10 14:57:09 +01:00
parent 5cf027bdc4
commit a2a81f5a7f
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
1 changed files with 18 additions and 15 deletions

View File

@ -52,16 +52,16 @@ export {
// ---------------------------------------------------------------------------
export async function updateVideo (req: express.Request, res: express.Response) {
const videoInstance = res.locals.videoAll
const videoFieldsSave = videoInstance.toJSON()
const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON())
const videoFromReq = res.locals.videoAll
const videoFieldsSave = videoFromReq.toJSON()
const oldVideoAuditView = new VideoAuditView(videoFromReq.toFormattedDetailsJSON())
const videoInfoToUpdate: VideoUpdate = req.body
const wasConfidentialVideo = videoInstance.isConfidential()
const hadPrivacyForFederation = videoInstance.hasPrivacyForFederation()
const wasConfidentialVideo = videoFromReq.isConfidential()
const hadPrivacyForFederation = videoFromReq.hasPrivacyForFederation()
const [ thumbnailModel, previewModel ] = await buildVideoThumbnailsFromReq({
video: videoInstance,
video: videoFromReq,
files: req.files,
fallback: () => Promise.resolve(undefined),
automaticallyGenerated: false
@ -69,8 +69,11 @@ export async function updateVideo (req: express.Request, res: express.Response)
try {
const videoInstanceUpdated = await sequelizeTypescript.transaction(async t => {
// Refresh video since thumbnails to prevent concurrent updates
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoFromReq.id, t)
const sequelizeOptions = { transaction: t }
const oldVideoChannel = videoInstance.VideoChannel
const oldVideoChannel = video.VideoChannel
const keysToUpdate: (keyof VideoUpdate & FilteredModelAttributes<VideoModel>)[] = [
'name',
@ -86,25 +89,25 @@ export async function updateVideo (req: express.Request, res: express.Response)
]
for (const key of keysToUpdate) {
if (videoInfoToUpdate[key] !== undefined) videoInstance.set(key, videoInfoToUpdate[key])
if (videoInfoToUpdate[key] !== undefined) video.set(key, videoInfoToUpdate[key])
}
if (videoInfoToUpdate.originallyPublishedAt !== undefined && videoInfoToUpdate.originallyPublishedAt !== null) {
videoInstance.originallyPublishedAt = new Date(videoInfoToUpdate.originallyPublishedAt)
video.originallyPublishedAt = new Date(videoInfoToUpdate.originallyPublishedAt)
}
// Privacy update?
let isNewVideo = false
if (videoInfoToUpdate.privacy !== undefined) {
isNewVideo = await updateVideoPrivacy({ videoInstance, videoInfoToUpdate, hadPrivacyForFederation, transaction: t })
isNewVideo = await updateVideoPrivacy({ videoInstance: video, videoInfoToUpdate, hadPrivacyForFederation, transaction: t })
}
// Force updatedAt attribute change
if (!videoInstance.changed()) {
await videoInstance.setAsRefreshed()
if (!video.changed()) {
await video.setAsRefreshed()
}
const videoInstanceUpdated = await videoInstance.save(sequelizeOptions) as MVideoFullLight
const videoInstanceUpdated = await video.save(sequelizeOptions) as MVideoFullLight
// Thumbnail & preview updates?
if (thumbnailModel) await videoInstanceUpdated.addAndSaveThumbnail(thumbnailModel, t)
@ -141,7 +144,7 @@ export async function updateVideo (req: express.Request, res: express.Response)
new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()),
oldVideoAuditView
)
logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid, lTags(videoInstance.uuid))
logger.info('Video with name %s and uuid %s updated.', video.name, video.uuid, lTags(video.uuid))
return videoInstanceUpdated
})
@ -155,7 +158,7 @@ export async function updateVideo (req: express.Request, res: express.Response)
// Force fields we want to update
// If the transaction is retried, sequelize will think the object has not changed
// So it will skip the SQL request, even if the last one was ROLLBACKed!
resetSequelizeInstance(videoInstance, videoFieldsSave)
resetSequelizeInstance(videoFromReq, videoFieldsSave)
throw err
}