From 90d4bb8125e80c8060416d4d135ddeaf0a622ede Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 13 Jun 2018 14:27:40 +0200 Subject: Refractor retry transaction function --- server/controllers/api/users.ts | 52 ++++++++---------------- server/controllers/api/video-channel.ts | 55 ++++++-------------------- server/controllers/api/videos/abuse.ts | 25 ++++++------ server/controllers/api/videos/comment.ts | 68 ++++++++++++-------------------- server/controllers/api/videos/index.ts | 62 ++++++++--------------------- server/controllers/api/videos/rate.ts | 18 ++------- 6 files changed, 84 insertions(+), 196 deletions(-) (limited to 'server/controllers/api') diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index 2b40c44d9..0aeb77964 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts @@ -4,7 +4,6 @@ import { extname, join } from 'path' import * as uuidv4 from 'uuid/v4' import * as RateLimit from 'express-rate-limit' import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared' -import { retryTransactionWrapper } from '../../helpers/database-utils' import { processImage } from '../../helpers/image-utils' import { logger } from '../../helpers/logger' import { getFormattedObjects } from '../../helpers/utils' @@ -16,6 +15,7 @@ import { Redis } from '../../lib/redis' import { createUserAccountAndChannel } from '../../lib/user' import { asyncMiddleware, + asyncRetryTransactionMiddleware, authenticate, ensureUserHasRight, ensureUserRegistrationAllowed, @@ -102,14 +102,14 @@ usersRouter.post('/', authenticate, ensureUserHasRight(UserRight.MANAGE_USERS), asyncMiddleware(usersAddValidator), - asyncMiddleware(createUserRetryWrapper) + asyncRetryTransactionMiddleware(createUser) ) usersRouter.post('/register', asyncMiddleware(ensureUserRegistrationAllowed), ensureUserRegistrationAllowedForIP, asyncMiddleware(usersRegisterValidator), - asyncMiddleware(registerUserRetryWrapper) + asyncRetryTransactionMiddleware(registerUser) ) usersRouter.put('/me', @@ -178,26 +178,7 @@ async function getUserVideos (req: express.Request, res: express.Response, next: return res.json(getFormattedObjects(resultList.data, resultList.total, { additionalAttributes })) } -async function createUserRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req ], - errorMessage: 'Cannot insert the user with many retries.' - } - - const { user, account } = await retryTransactionWrapper(createUser, options) - - return res.json({ - user: { - id: user.id, - account: { - id: account.id, - uuid: account.Actor.uuid - } - } - }).end() -} - -async function createUser (req: express.Request) { +async function createUser (req: express.Request, res: express.Response) { const body: UserCreate = req.body const userToCreate = new UserModel({ username: body.username, @@ -213,21 +194,18 @@ async function createUser (req: express.Request) { logger.info('User %s with its channel and account created.', body.username) - return { user, account } -} - -async function registerUserRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req ], - errorMessage: 'Cannot insert the user with many retries.' - } - - await retryTransactionWrapper(registerUser, options) - - return res.type('json').status(204).end() + return res.json({ + user: { + id: user.id, + account: { + id: account.id, + uuid: account.Actor.uuid + } + } + }).end() } -async function registerUser (req: express.Request) { +async function registerUser (req: express.Request, res: express.Response) { const body: UserCreate = req.body const user = new UserModel({ @@ -243,6 +221,8 @@ async function registerUser (req: express.Request) { await createUserAccountAndChannel(user) logger.info('User %s with its channel and account registered.', body.username) + + return res.type('json').status(204).end() } async function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) { diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index 263eb2a8a..61e72125f 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts @@ -2,6 +2,7 @@ import * as express from 'express' import { getFormattedObjects, resetSequelizeInstance } from '../../helpers/utils' import { asyncMiddleware, + asyncRetryTransactionMiddleware, authenticate, optionalAuthenticate, paginationValidator, @@ -20,7 +21,6 @@ import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' import { createVideoChannel } from '../../lib/video-channel' import { isNSFWHidden } from '../../helpers/express-utils' import { setAsyncActorKeys } from '../../lib/activitypub' -import { retryTransactionWrapper } from '../../helpers/database-utils' import { AccountModel } from '../../models/account/account' import { sequelizeTypescript } from '../../initializers' import { logger } from '../../helpers/logger' @@ -39,19 +39,19 @@ videoChannelRouter.get('/', videoChannelRouter.post('/', authenticate, videoChannelsAddValidator, - asyncMiddleware(addVideoChannelRetryWrapper) + asyncRetryTransactionMiddleware(addVideoChannel) ) videoChannelRouter.put('/:id', authenticate, asyncMiddleware(videoChannelsUpdateValidator), - updateVideoChannelRetryWrapper + asyncRetryTransactionMiddleware(updateVideoChannel) ) videoChannelRouter.delete('/:id', authenticate, asyncMiddleware(videoChannelsRemoveValidator), - asyncMiddleware(removeVideoChannelRetryWrapper) + asyncRetryTransactionMiddleware(removeVideoChannel) ) videoChannelRouter.get('/:id', @@ -83,23 +83,6 @@ async function listVideoChannels (req: express.Request, res: express.Response, n return res.json(getFormattedObjects(resultList.data, resultList.total)) } -// Wrapper to video channel add that retry the async function if there is a database error -// We need this because we run the transaction in SERIALIZABLE isolation that can fail -async function addVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot insert the video video channel with many retries.' - } - - const videoChannel = await retryTransactionWrapper(addVideoChannel, options) - return res.json({ - videoChannel: { - id: videoChannel.id, - uuid: videoChannel.Actor.uuid - } - }).end() -} - async function addVideoChannel (req: express.Request, res: express.Response) { const videoChannelInfo: VideoChannelCreate = req.body const account: AccountModel = res.locals.oauth.token.User.Account @@ -113,18 +96,12 @@ async function addVideoChannel (req: express.Request, res: express.Response) { logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid) - return videoChannelCreated -} - -async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot update the video with many retries.' - } - - await retryTransactionWrapper(updateVideoChannel, options) - - return res.type('json').status(204).end() + return res.json({ + videoChannel: { + id: videoChannelCreated.id, + uuid: videoChannelCreated.Actor.uuid + } + }).end() } async function updateVideoChannel (req: express.Request, res: express.Response) { @@ -157,15 +134,6 @@ async function updateVideoChannel (req: express.Request, res: express.Response) throw err } -} - -async function removeVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot remove the video channel with many retries.' - } - - await retryTransactionWrapper(removeVideoChannel, options) return res.type('json').status(204).end() } @@ -173,12 +141,13 @@ async function removeVideoChannelRetryWrapper (req: express.Request, res: expres async function removeVideoChannel (req: express.Request, res: express.Response) { const videoChannelInstance: VideoChannelModel = res.locals.videoChannel - return sequelizeTypescript.transaction(async t => { + await sequelizeTypescript.transaction(async t => { await videoChannelInstance.destroy({ transaction: t }) logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) }) + return res.type('json').status(204).end() } async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) { diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index 61ff3af4f..3413ae894 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts @@ -1,12 +1,18 @@ import * as express from 'express' import { UserRight, VideoAbuseCreate } from '../../../../shared' -import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { getFormattedObjects } from '../../../helpers/utils' import { sequelizeTypescript } from '../../../initializers' import { sendVideoAbuse } from '../../../lib/activitypub/send' import { - asyncMiddleware, authenticate, ensureUserHasRight, paginationValidator, setDefaultSort, setDefaultPagination, videoAbuseReportValidator, + asyncMiddleware, + asyncRetryTransactionMiddleware, + authenticate, + ensureUserHasRight, + paginationValidator, + setDefaultPagination, + setDefaultSort, + videoAbuseReportValidator, videoAbusesSortValidator } from '../../../middlewares' import { AccountModel } from '../../../models/account/account' @@ -27,7 +33,7 @@ abuseVideoRouter.get('/abuse', abuseVideoRouter.post('/:id/abuse', authenticate, asyncMiddleware(videoAbuseReportValidator), - asyncMiddleware(reportVideoAbuseRetryWrapper) + asyncRetryTransactionMiddleware(reportVideoAbuse) ) // --------------------------------------------------------------------------- @@ -44,17 +50,6 @@ async function listVideoAbuses (req: express.Request, res: express.Response, nex return res.json(getFormattedObjects(resultList.data, resultList.total)) } -async function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot report abuse to the video with many retries.' - } - - await retryTransactionWrapper(reportVideoAbuse, options) - - return res.type('json').status(204).end() -} - async function reportVideoAbuse (req: express.Request, res: express.Response) { const videoInstance = res.locals.video as VideoModel const reporterAccount = res.locals.oauth.token.User.Account as AccountModel @@ -77,4 +72,6 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) { }) logger.info('Abuse report for video %s created.', videoInstance.name) + + return res.type('json').status(204).end() } diff --git a/server/controllers/api/videos/comment.ts b/server/controllers/api/videos/comment.ts index f8a669e35..bbeb0d557 100644 --- a/server/controllers/api/videos/comment.ts +++ b/server/controllers/api/videos/comment.ts @@ -1,15 +1,24 @@ import * as express from 'express' import { ResultList } from '../../../../shared/models' import { VideoCommentCreate } from '../../../../shared/models/videos/video-comment.model' -import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { getFormattedObjects } from '../../../helpers/utils' import { sequelizeTypescript } from '../../../initializers' import { buildFormattedCommentTree, createVideoComment } from '../../../lib/video-comment' -import { asyncMiddleware, authenticate, paginationValidator, setDefaultSort, setDefaultPagination } from '../../../middlewares' +import { + asyncMiddleware, + asyncRetryTransactionMiddleware, + authenticate, + paginationValidator, + setDefaultPagination, + setDefaultSort +} from '../../../middlewares' import { videoCommentThreadsSortValidator } from '../../../middlewares/validators' import { - addVideoCommentReplyValidator, addVideoCommentThreadValidator, listVideoCommentThreadsValidator, listVideoThreadCommentsValidator, + addVideoCommentReplyValidator, + addVideoCommentThreadValidator, + listVideoCommentThreadsValidator, + listVideoThreadCommentsValidator, removeVideoCommentValidator } from '../../../middlewares/validators/video-comments' import { VideoModel } from '../../../models/video/video' @@ -33,17 +42,17 @@ videoCommentRouter.get('/:videoId/comment-threads/:threadId', videoCommentRouter.post('/:videoId/comment-threads', authenticate, asyncMiddleware(addVideoCommentThreadValidator), - asyncMiddleware(addVideoCommentThreadRetryWrapper) + asyncRetryTransactionMiddleware(addVideoCommentThread) ) videoCommentRouter.post('/:videoId/comments/:commentId', authenticate, asyncMiddleware(addVideoCommentReplyValidator), - asyncMiddleware(addVideoCommentReplyRetryWrapper) + asyncRetryTransactionMiddleware(addVideoCommentReply) ) videoCommentRouter.delete('/:videoId/comments/:commentId', authenticate, asyncMiddleware(removeVideoCommentValidator), - asyncMiddleware(removeVideoCommentRetryWrapper) + asyncRetryTransactionMiddleware(removeVideoComment) ) // --------------------------------------------------------------------------- @@ -86,23 +95,10 @@ async function listVideoThreadComments (req: express.Request, res: express.Respo return res.json(buildFormattedCommentTree(resultList)) } -async function addVideoCommentThreadRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot insert the video comment thread with many retries.' - } - - const comment = await retryTransactionWrapper(addVideoCommentThread, options) - - res.json({ - comment: comment.toFormattedJSON() - }).end() -} - -function addVideoCommentThread (req: express.Request, res: express.Response) { +async function addVideoCommentThread (req: express.Request, res: express.Response) { const videoCommentInfo: VideoCommentCreate = req.body - return sequelizeTypescript.transaction(async t => { + const comment = await sequelizeTypescript.transaction(async t => { return createVideoComment({ text: videoCommentInfo.text, inReplyToComment: null, @@ -110,25 +106,16 @@ function addVideoCommentThread (req: express.Request, res: express.Response) { account: res.locals.oauth.token.User.Account }, t) }) -} -async function addVideoCommentReplyRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot insert the video comment reply with many retries.' - } - - const comment = await retryTransactionWrapper(addVideoCommentReply, options) - - res.json({ + return res.json({ comment: comment.toFormattedJSON() }).end() } -function addVideoCommentReply (req: express.Request, res: express.Response, next: express.NextFunction) { +async function addVideoCommentReply (req: express.Request, res: express.Response) { const videoCommentInfo: VideoCommentCreate = req.body - return sequelizeTypescript.transaction(async t => { + const comment = await sequelizeTypescript.transaction(async t => { return createVideoComment({ text: videoCommentInfo.text, inReplyToComment: res.locals.videoComment, @@ -136,17 +123,10 @@ function addVideoCommentReply (req: express.Request, res: express.Response, next account: res.locals.oauth.token.User.Account }, t) }) -} - -async function removeVideoCommentRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot remove the video comment with many retries.' - } - await retryTransactionWrapper(removeVideoComment, options) - - return res.type('json').status(204).end() + return res.json({ + comment: comment.toFormattedJSON() + }).end() } async function removeVideoComment (req: express.Request, res: express.Response) { @@ -157,4 +137,6 @@ async function removeVideoComment (req: express.Request, res: express.Response) }) logger.info('Video comment %d deleted.', videoCommentInstance.id) + + return res.type('json').status(204).end() } diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 9d9b2b0e1..78963d89b 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -2,7 +2,6 @@ import * as express from 'express' import { extname, join } from 'path' import { VideoCreate, VideoPrivacy, VideoState, VideoUpdate } from '../../../../shared' import { renamePromise } from '../../../helpers/core-utils' -import { retryTransactionWrapper } from '../../../helpers/database-utils' import { getVideoFileResolution } from '../../../helpers/ffmpeg-utils' import { processImage } from '../../../helpers/image-utils' import { logger } from '../../../helpers/logger' @@ -30,6 +29,7 @@ import { JobQueue } from '../../../lib/job-queue' import { Redis } from '../../../lib/redis' import { asyncMiddleware, + asyncRetryTransactionMiddleware, authenticate, optionalAuthenticate, paginationValidator, @@ -104,13 +104,13 @@ videosRouter.put('/:id', authenticate, reqVideoFileUpdate, asyncMiddleware(videosUpdateValidator), - asyncMiddleware(updateVideoRetryWrapper) + asyncRetryTransactionMiddleware(updateVideo) ) videosRouter.post('/upload', authenticate, reqVideoFileAdd, asyncMiddleware(videosAddValidator), - asyncMiddleware(addVideoRetryWrapper) + asyncRetryTransactionMiddleware(addVideo) ) videosRouter.get('/:id/description', @@ -129,7 +129,7 @@ videosRouter.post('/:id/views', videosRouter.delete('/:id', authenticate, asyncMiddleware(videosRemoveValidator), - asyncMiddleware(removeVideoRetryWrapper) + asyncRetryTransactionMiddleware(removeVideo) ) // --------------------------------------------------------------------------- @@ -156,25 +156,8 @@ function listVideoPrivacies (req: express.Request, res: express.Response) { res.json(VIDEO_PRIVACIES) } -// Wrapper to video add that retry the function if there is a database error -// We need this because we run the transaction in SERIALIZABLE isolation that can fail -async function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res, req.files['videofile'][0] ], - errorMessage: 'Cannot insert the video with many retries.' - } - - const video = await retryTransactionWrapper(addVideo, options) - - res.json({ - video: { - id: video.id, - uuid: video.uuid - } - }).end() -} - -async function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) { +async function addVideo (req: express.Request, res: express.Response) { + const videoPhysicalFile = req.files['videofile'][0] const videoInfo: VideoCreate = req.body // Prepare data so we don't block the transaction @@ -272,18 +255,12 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi await JobQueue.Instance.createJob({ type: 'video-file', payload: dataInput }) } - return videoCreated -} - -async function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot update the video with many retries.' - } - - await retryTransactionWrapper(updateVideo, options) - - return res.type('json').status(204).end() + return res.json({ + video: { + id: videoCreated.id, + uuid: videoCreated.uuid + } + }).end() } async function updateVideo (req: express.Request, res: express.Response) { @@ -360,6 +337,8 @@ async function updateVideo (req: express.Request, res: express.Response) { throw err } + + return res.type('json').status(204).end() } function getVideo (req: express.Request, res: express.Response) { @@ -414,17 +393,6 @@ async function listVideos (req: express.Request, res: express.Response, next: ex return res.json(getFormattedObjects(resultList.data, resultList.total)) } -async function removeVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot remove the video with many retries.' - } - - await retryTransactionWrapper(removeVideo, options) - - return res.type('json').status(204).end() -} - async function removeVideo (req: express.Request, res: express.Response) { const videoInstance: VideoModel = res.locals.video @@ -433,6 +401,8 @@ async function removeVideo (req: express.Request, res: express.Response) { }) logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid) + + return res.type('json').status(204).end() } async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { diff --git a/server/controllers/api/videos/rate.ts b/server/controllers/api/videos/rate.ts index 23e9de9f3..9d63b5821 100644 --- a/server/controllers/api/videos/rate.ts +++ b/server/controllers/api/videos/rate.ts @@ -1,10 +1,9 @@ import * as express from 'express' import { UserVideoRateUpdate } from '../../../../shared' -import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { sequelizeTypescript, VIDEO_RATE_TYPES } from '../../../initializers' import { sendVideoRateChange } from '../../../lib/activitypub' -import { asyncMiddleware, authenticate, videoRateValidator } from '../../../middlewares' +import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoRateValidator } from '../../../middlewares' import { AccountModel } from '../../../models/account/account' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' import { VideoModel } from '../../../models/video/video' @@ -14,7 +13,7 @@ const rateVideoRouter = express.Router() rateVideoRouter.put('/:id/rate', authenticate, asyncMiddleware(videoRateValidator), - asyncMiddleware(rateVideoRetryWrapper) + asyncRetryTransactionMiddleware(rateVideo) ) // --------------------------------------------------------------------------- @@ -25,17 +24,6 @@ export { // --------------------------------------------------------------------------- -async function rateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { - const options = { - arguments: [ req, res ], - errorMessage: 'Cannot update the user video rate.' - } - - await retryTransactionWrapper(rateVideo, options) - - return res.type('json').status(204).end() -} - async function rateVideo (req: express.Request, res: express.Response) { const body: UserVideoRateUpdate = req.body const rateType = body.rating @@ -87,4 +75,6 @@ async function rateVideo (req: express.Request, res: express.Response) { }) logger.info('Account video rate for video %s of account %s updated.', videoInstance.name, accountInstance.name) + + return res.type('json').status(204).end() } -- cgit v1.2.3