Fix concurrency error when deleting a video
authorChocobozzz <florian.bigard@gmail.com>
Tue, 12 Sep 2017 12:17:46 +0000 (14:17 +0200)
committerChocobozzz <florian.bigard@gmail.com>
Tue, 12 Sep 2017 12:17:46 +0000 (14:17 +0200)
server/controllers/api/videos/index.ts
server/lib/friends.ts
server/models/video/video.ts

index 7a9cd9d37486b03a01512b2a19376181c1f22a49..6fa84c8012641796ca49ce7be76cc6bf73d86f1f 100644 (file)
@@ -45,6 +45,7 @@ import { VideoCreate, VideoUpdate } from '../../../../shared'
 import { abuseVideoRouter } from './abuse'
 import { blacklistRouter } from './blacklist'
 import { rateVideoRouter } from './rate'
+import { VideoInstance } from '../../../models/video/video-interface'
 
 const videosRouter = express.Router()
 
@@ -106,7 +107,7 @@ videosRouter.get('/:id',
 videosRouter.delete('/:id',
   authenticate,
   videosRemoveValidator,
-  removeVideo
+  removeVideoRetryWrapper
 )
 
 videosRouter.get('/search/:value',
@@ -291,7 +292,6 @@ function updateVideoRetryWrapper (req: express.Request, res: express.Response, n
 
   retryTransactionWrapper(updateVideo, options)
     .then(() => {
-      // TODO : include Location of the new video -> 201
       return res.type('json').status(204).end()
     })
     .catch(err => next(err))
@@ -396,18 +396,32 @@ function listVideos (req: express.Request, res: express.Response, next: express.
     .catch(err => next(err))
 }
 
-function removeVideo (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const videoInstance = res.locals.video
+function removeVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
+  const options = {
+    arguments: [ req, res ],
+    errorMessage: 'Cannot remove the video with many retries.'
+  }
 
-  videoInstance.destroy()
+  retryTransactionWrapper(removeVideo, options)
     .then(() => {
-      logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
-      res.type('json').status(204).end()
-    })
-    .catch(err => {
-      logger.error('Errors when removed the video.', err)
-      return next(err)
+      return res.type('json').status(204).end()
     })
+    .catch(err => next(err))
+}
+
+function removeVideo (req: express.Request, res: express.Response) {
+  const videoInstance: VideoInstance = res.locals.video
+
+  return db.sequelize.transaction(t => {
+    return videoInstance.destroy({ transaction: t })
+  })
+  .then(() => {
+    logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
+  })
+  .catch(err => {
+    logger.error('Errors when removed the video.', err)
+    throw err
+  })
 }
 
 function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
index 3f0ce3f33f602955ed9db15b7466052b35e6fba6..ea9ddbe8d3a2776b2fa373584beaedbc6d459bde 100644 (file)
@@ -80,12 +80,12 @@ function updateVideoToFriends (videoData: RemoteVideoUpdateData, transaction: Se
   return createRequest(options)
 }
 
-function removeVideoToFriends (videoParams: RemoteVideoRemoveData) {
+function removeVideoToFriends (videoParams: RemoteVideoRemoveData, transaction: Sequelize.Transaction) {
   const options = {
     type: ENDPOINT_ACTIONS.REMOVE,
     endpoint: REQUEST_ENDPOINTS.VIDEOS,
     data: videoParams,
-    transaction: null
+    transaction
   }
   return createRequest(options)
 }
index 1134525f02b4798bdb77f40d4ae4b2d148b31b66..e011c3b4dab1c0036dcc3e386fcc4704ead51f49 100644 (file)
@@ -300,7 +300,7 @@ function associate (models) {
   })
 }
 
-function afterDestroy (video: VideoInstance) {
+function afterDestroy (video: VideoInstance, options: { transaction: Sequelize.Transaction }) {
   const tasks = []
 
   tasks.push(
@@ -314,10 +314,10 @@ function afterDestroy (video: VideoInstance) {
 
     tasks.push(
       video.removePreview(),
-      removeVideoToFriends(removeVideoToFriendsParams)
+      removeVideoToFriends(removeVideoToFriendsParams, options.transaction)
     )
 
-    // TODO: check files is populated
+    // Remove physical files and torrents
     video.VideoFiles.forEach(file => {
       video.removeFile(file),
       video.removeTorrent(file)