diff options
author | Chocobozzz <me@florianbigard.com> | 2023-02-14 08:59:27 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-02-14 09:03:22 +0100 |
commit | 4565774669bc3c1b11cc726d577946953dbe53c5 (patch) | |
tree | ee0e41e06245861a0de896684caa388f82cc3470 /server | |
parent | 4c61660a0ab6224079c67d8282b282772a0772e4 (diff) | |
download | PeerTube-4565774669bc3c1b11cc726d577946953dbe53c5.tar.gz PeerTube-4565774669bc3c1b11cc726d577946953dbe53c5.tar.zst PeerTube-4565774669bc3c1b11cc726d577946953dbe53c5.zip |
Fix retrying update on sql serialization conflict
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/video-channel.ts | 6 | ||||
-rw-r--r-- | server/controllers/api/video-playlist.ts | 6 | ||||
-rw-r--r-- | server/controllers/api/videos/update.ts | 6 | ||||
-rw-r--r-- | server/helpers/database-utils.ts | 6 | ||||
-rw-r--r-- | server/lib/activitypub/actors/updater.ts | 15 | ||||
-rw-r--r-- | server/lib/activitypub/videos/updater.ts | 8 |
6 files changed, 14 insertions, 33 deletions
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index d7c92952a..5b9fb794a 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts | |||
@@ -273,7 +273,6 @@ async function addVideoChannel (req: express.Request, res: express.Response) { | |||
273 | 273 | ||
274 | async function updateVideoChannel (req: express.Request, res: express.Response) { | 274 | async function updateVideoChannel (req: express.Request, res: express.Response) { |
275 | const videoChannelInstance = res.locals.videoChannel | 275 | const videoChannelInstance = res.locals.videoChannel |
276 | const videoChannelFieldsSave = videoChannelInstance.toJSON() | ||
277 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) | 276 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) |
278 | const videoChannelInfoToUpdate = req.body as VideoChannelUpdate | 277 | const videoChannelInfoToUpdate = req.body as VideoChannelUpdate |
279 | let doBulkVideoUpdate = false | 278 | let doBulkVideoUpdate = false |
@@ -309,10 +308,9 @@ async function updateVideoChannel (req: express.Request, res: express.Response) | |||
309 | } catch (err) { | 308 | } catch (err) { |
310 | logger.debug('Cannot update the video channel.', { err }) | 309 | logger.debug('Cannot update the video channel.', { err }) |
311 | 310 | ||
312 | // Force fields we want to update | ||
313 | // If the transaction is retried, sequelize will think the object has not changed | 311 | // If the transaction is retried, sequelize will think the object has not changed |
314 | // So it will skip the SQL request, even if the last one was ROLLBACKed! | 312 | // So we need to restore the previous fields |
315 | resetSequelizeInstance(videoChannelInstance, videoChannelFieldsSave) | 313 | resetSequelizeInstance(videoChannelInstance) |
316 | 314 | ||
317 | throw err | 315 | throw err |
318 | } | 316 | } |
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts index 947f7ca77..bcb60e265 100644 --- a/server/controllers/api/video-playlist.ts +++ b/server/controllers/api/video-playlist.ts | |||
@@ -210,7 +210,6 @@ async function addVideoPlaylist (req: express.Request, res: express.Response) { | |||
210 | 210 | ||
211 | async function updateVideoPlaylist (req: express.Request, res: express.Response) { | 211 | async function updateVideoPlaylist (req: express.Request, res: express.Response) { |
212 | const videoPlaylistInstance = res.locals.videoPlaylistFull | 212 | const videoPlaylistInstance = res.locals.videoPlaylistFull |
213 | const videoPlaylistFieldsSave = videoPlaylistInstance.toJSON() | ||
214 | const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate | 213 | const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate |
215 | 214 | ||
216 | const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE | 215 | const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE |
@@ -275,10 +274,9 @@ async function updateVideoPlaylist (req: express.Request, res: express.Response) | |||
275 | } catch (err) { | 274 | } catch (err) { |
276 | logger.debug('Cannot update the video playlist.', { err }) | 275 | logger.debug('Cannot update the video playlist.', { err }) |
277 | 276 | ||
278 | // Force fields we want to update | ||
279 | // If the transaction is retried, sequelize will think the object has not changed | 277 | // If the transaction is retried, sequelize will think the object has not changed |
280 | // So it will skip the SQL request, even if the last one was ROLLBACKed! | 278 | // So we need to restore the previous fields |
281 | resetSequelizeInstance(videoPlaylistInstance, videoPlaylistFieldsSave) | 279 | resetSequelizeInstance(videoPlaylistInstance) |
282 | 280 | ||
283 | throw err | 281 | throw err |
284 | } | 282 | } |
diff --git a/server/controllers/api/videos/update.ts b/server/controllers/api/videos/update.ts index 260dee2b9..e6197c4b1 100644 --- a/server/controllers/api/videos/update.ts +++ b/server/controllers/api/videos/update.ts | |||
@@ -45,7 +45,6 @@ export { | |||
45 | 45 | ||
46 | async function updateVideo (req: express.Request, res: express.Response) { | 46 | async function updateVideo (req: express.Request, res: express.Response) { |
47 | const videoFromReq = res.locals.videoAll | 47 | const videoFromReq = res.locals.videoAll |
48 | const videoFieldsSave = videoFromReq.toJSON() | ||
49 | const oldVideoAuditView = new VideoAuditView(videoFromReq.toFormattedDetailsJSON()) | 48 | const oldVideoAuditView = new VideoAuditView(videoFromReq.toFormattedDetailsJSON()) |
50 | const videoInfoToUpdate: VideoUpdate = req.body | 49 | const videoInfoToUpdate: VideoUpdate = req.body |
51 | 50 | ||
@@ -151,10 +150,9 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
151 | isNewVideo | 150 | isNewVideo |
152 | }) | 151 | }) |
153 | } catch (err) { | 152 | } catch (err) { |
154 | // Force fields we want to update | ||
155 | // If the transaction is retried, sequelize will think the object has not changed | 153 | // If the transaction is retried, sequelize will think the object has not changed |
156 | // So it will skip the SQL request, even if the last one was ROLLBACKed! | 154 | // So we need to restore the previous fields |
157 | resetSequelizeInstance(videoFromReq, videoFieldsSave) | 155 | resetSequelizeInstance(videoFromReq) |
158 | 156 | ||
159 | throw err | 157 | throw err |
160 | } finally { | 158 | } finally { |
diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts index 627381086..0e6b35503 100644 --- a/server/helpers/database-utils.ts +++ b/server/helpers/database-utils.ts | |||
@@ -78,10 +78,8 @@ function updateInstanceWithAnother <M, T extends U, U extends Model<M>> (instanc | |||
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | function resetSequelizeInstance (instance: Model<any>, savedFields: object) { | 81 | function resetSequelizeInstance <T> (instance: Model<T>) { |
82 | Object.keys(savedFields).forEach(key => { | 82 | instance.set(instance.previous()) |
83 | instance[key] = savedFields[key] | ||
84 | }) | ||
85 | } | 83 | } |
86 | 84 | ||
87 | function filterNonExistingModels <T extends { hasSameUniqueKeysThan (other: T): boolean }> ( | 85 | function filterNonExistingModels <T extends { hasSameUniqueKeysThan (other: T): boolean }> ( |
diff --git a/server/lib/activitypub/actors/updater.ts b/server/lib/activitypub/actors/updater.ts index fe94af9f1..137980460 100644 --- a/server/lib/activitypub/actors/updater.ts +++ b/server/lib/activitypub/actors/updater.ts | |||
@@ -13,19 +13,12 @@ export class APActorUpdater { | |||
13 | 13 | ||
14 | private accountOrChannel: MAccount | MChannel | 14 | private accountOrChannel: MAccount | MChannel |
15 | 15 | ||
16 | private readonly actorFieldsSave: object | ||
17 | private readonly accountOrChannelFieldsSave: object | ||
18 | |||
19 | constructor ( | 16 | constructor ( |
20 | private readonly actorObject: ActivityPubActor, | 17 | private readonly actorObject: ActivityPubActor, |
21 | private readonly actor: MActorFull | 18 | private readonly actor: MActorFull |
22 | ) { | 19 | ) { |
23 | this.actorFieldsSave = this.actor.toJSON() | ||
24 | |||
25 | if (this.actorObject.type === 'Group') this.accountOrChannel = this.actor.VideoChannel | 20 | if (this.actorObject.type === 'Group') this.accountOrChannel = this.actor.VideoChannel |
26 | else this.accountOrChannel = this.actor.Account | 21 | else this.accountOrChannel = this.actor.Account |
27 | |||
28 | this.accountOrChannelFieldsSave = this.accountOrChannel.toJSON() | ||
29 | } | 22 | } |
30 | 23 | ||
31 | async update () { | 24 | async update () { |
@@ -58,12 +51,12 @@ export class APActorUpdater { | |||
58 | 51 | ||
59 | logger.info('Remote account %s updated', this.actorObject.url) | 52 | logger.info('Remote account %s updated', this.actorObject.url) |
60 | } catch (err) { | 53 | } catch (err) { |
61 | if (this.actor !== undefined && this.actorFieldsSave !== undefined) { | 54 | if (this.actor !== undefined) { |
62 | resetSequelizeInstance(this.actor, this.actorFieldsSave) | 55 | resetSequelizeInstance(this.actor) |
63 | } | 56 | } |
64 | 57 | ||
65 | if (this.accountOrChannel !== undefined && this.accountOrChannelFieldsSave !== undefined) { | 58 | if (this.accountOrChannel !== undefined) { |
66 | resetSequelizeInstance(this.accountOrChannel, this.accountOrChannelFieldsSave) | 59 | resetSequelizeInstance(this.accountOrChannel) |
67 | } | 60 | } |
68 | 61 | ||
69 | // This is just a debug because we will retry the insert | 62 | // This is just a debug because we will retry the insert |
diff --git a/server/lib/activitypub/videos/updater.ts b/server/lib/activitypub/videos/updater.ts index 32cbf7e07..0bf32f440 100644 --- a/server/lib/activitypub/videos/updater.ts +++ b/server/lib/activitypub/videos/updater.ts | |||
@@ -13,8 +13,6 @@ export class APVideoUpdater extends APVideoAbstractBuilder { | |||
13 | private readonly wasPrivateVideo: boolean | 13 | private readonly wasPrivateVideo: boolean |
14 | private readonly wasUnlistedVideo: boolean | 14 | private readonly wasUnlistedVideo: boolean |
15 | 15 | ||
16 | private readonly videoFieldsSave: any | ||
17 | |||
18 | private readonly oldVideoChannel: MChannelAccountLight | 16 | private readonly oldVideoChannel: MChannelAccountLight |
19 | 17 | ||
20 | protected lTags: LoggerTagsFn | 18 | protected lTags: LoggerTagsFn |
@@ -30,8 +28,6 @@ export class APVideoUpdater extends APVideoAbstractBuilder { | |||
30 | 28 | ||
31 | this.oldVideoChannel = this.video.VideoChannel | 29 | this.oldVideoChannel = this.video.VideoChannel |
32 | 30 | ||
33 | this.videoFieldsSave = this.video.toJSON() | ||
34 | |||
35 | this.lTags = loggerTagsFactory('ap', 'video', 'update', video.uuid, video.url) | 31 | this.lTags = loggerTagsFactory('ap', 'video', 'update', video.uuid, video.url) |
36 | } | 32 | } |
37 | 33 | ||
@@ -156,8 +152,8 @@ export class APVideoUpdater extends APVideoAbstractBuilder { | |||
156 | } | 152 | } |
157 | 153 | ||
158 | private catchUpdateError (err: Error) { | 154 | private catchUpdateError (err: Error) { |
159 | if (this.video !== undefined && this.videoFieldsSave !== undefined) { | 155 | if (this.video !== undefined) { |
160 | resetSequelizeInstance(this.video, this.videoFieldsSave) | 156 | resetSequelizeInstance(this.video) |
161 | } | 157 | } |
162 | 158 | ||
163 | // This is just a debug because we will retry the insert | 159 | // This is just a debug because we will retry the insert |