aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/+videos/+video-watch/shared/information/video-alert.component.html4
-rw-r--r--client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts4
-rw-r--r--client/src/app/shared/shared-video-miniature/video-miniature.component.ts4
-rw-r--r--scripts/create-move-video-storage-job.ts7
-rw-r--r--server/initializers/constants.ts3
-rw-r--r--server/lib/job-queue/handlers/move-to-object-storage.ts29
-rw-r--r--server/lib/video-state.ts11
-rw-r--r--server/models/video/video-job-info.ts15
-rw-r--r--shared/models/videos/video-state.enum.ts3
9 files changed, 64 insertions, 16 deletions
diff --git a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.html b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.html
index 6e5d0bcad..0c4d46714 100644
--- a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.html
+++ b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.html
@@ -2,6 +2,10 @@
2 Transcoding failed, this video may not work properly. 2 Transcoding failed, this video may not work properly.
3</div> 3</div>
4 4
5<div i18n class="alert alert-warning" *ngIf="isVideoMoveToObjectStorageFailed()">
6 Move to external storage failed, this video may not work properly.
7</div>
8
5<div i18n class="alert alert-warning" *ngIf="isVideoToImport()"> 9<div i18n class="alert alert-warning" *ngIf="isVideoToImport()">
6 The video is being imported, it will be available when the import is finished. 10 The video is being imported, it will be available when the import is finished.
7</div> 11</div>
diff --git a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts
index addea53c0..a3d3fa6fb 100644
--- a/client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/information/video-alert.component.ts
@@ -18,6 +18,10 @@ export class VideoAlertComponent {
18 return this.video && this.video.state.id === VideoState.TRANSCODING_FAILED 18 return this.video && this.video.state.id === VideoState.TRANSCODING_FAILED
19 } 19 }
20 20
21 isVideoMoveToObjectStorageFailed () {
22 return this.video && this.video.state.id === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED
23 }
24
21 isVideoToImport () { 25 isVideoToImport () {
22 return this.video && this.video.state.id === VideoState.TO_IMPORT 26 return this.video && this.video.state.id === VideoState.TO_IMPORT
23 } 27 }
diff --git a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts
index f387c38c2..847e401ed 100644
--- a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts
+++ b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts
@@ -179,6 +179,10 @@ export class VideoMiniatureComponent implements OnInit {
179 return $localize`Transcoding failed` 179 return $localize`Transcoding failed`
180 } 180 }
181 181
182 if (video.state.id === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED) {
183 return $localize`Move to external storage failed`
184 }
185
182 if (video.state.id === VideoState.TO_TRANSCODE && video.waitTranscoding === true) { 186 if (video.state.id === VideoState.TO_TRANSCODE && video.waitTranscoding === true) {
183 return $localize`Waiting transcoding` 187 return $localize`Waiting transcoding`
184 } 188 }
diff --git a/scripts/create-move-video-storage-job.ts b/scripts/create-move-video-storage-job.ts
index 699487f72..90c84b1d7 100644
--- a/scripts/create-move-video-storage-job.ts
+++ b/scripts/create-move-video-storage-job.ts
@@ -4,7 +4,7 @@ registerTSPaths()
4import { program } from 'commander' 4import { program } from 'commander'
5import { VideoModel } from '@server/models/video/video' 5import { VideoModel } from '@server/models/video/video'
6import { initDatabaseModels } from '@server/initializers/database' 6import { initDatabaseModels } from '@server/initializers/database'
7import { VideoStorage } from '@shared/models' 7import { VideoState, VideoStorage } from '@shared/models'
8import { moveToExternalStorageState } from '@server/lib/video-state' 8import { moveToExternalStorageState } from '@server/lib/video-state'
9import { JobQueue } from '@server/lib/job-queue' 9import { JobQueue } from '@server/lib/job-queue'
10import { CONFIG } from '@server/initializers/config' 10import { CONFIG } from '@server/initializers/config'
@@ -62,6 +62,11 @@ async function run () {
62 process.exit(-1) 62 process.exit(-1)
63 } 63 }
64 64
65 if (video.state === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE) {
66 console.error('This video is already being moved to external storage')
67 process.exit(-1)
68 }
69
65 ids.push(video.id) 70 ids.push(video.id)
66 } else { 71 } else {
67 ids = await VideoModel.listLocalIds() 72 ids = await VideoModel.listLocalIds()
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 57f7af789..7816561fd 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -427,7 +427,8 @@ const VIDEO_STATES: { [ id in VideoState ]: string } = {
427 [VideoState.WAITING_FOR_LIVE]: 'Waiting for livestream', 427 [VideoState.WAITING_FOR_LIVE]: 'Waiting for livestream',
428 [VideoState.LIVE_ENDED]: 'Livestream ended', 428 [VideoState.LIVE_ENDED]: 'Livestream ended',
429 [VideoState.TO_MOVE_TO_EXTERNAL_STORAGE]: 'To move to an external storage', 429 [VideoState.TO_MOVE_TO_EXTERNAL_STORAGE]: 'To move to an external storage',
430 [VideoState.TRANSCODING_FAILED]: 'Transcoding failed' 430 [VideoState.TRANSCODING_FAILED]: 'Transcoding failed',
431 [VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED]: 'External storage move failed'
431} 432}
432 433
433const VIDEO_IMPORT_STATES: { [ id in VideoImportState ]: string } = { 434const VIDEO_IMPORT_STATES: { [ id in VideoImportState ]: string } = {
diff --git a/server/lib/job-queue/handlers/move-to-object-storage.ts b/server/lib/job-queue/handlers/move-to-object-storage.ts
index b5eea0184..d9c415b2d 100644
--- a/server/lib/job-queue/handlers/move-to-object-storage.ts
+++ b/server/lib/job-queue/handlers/move-to-object-storage.ts
@@ -7,7 +7,7 @@ import { CONFIG } from '@server/initializers/config'
7import { P2P_MEDIA_LOADER_PEER_VERSION } from '@server/initializers/constants' 7import { P2P_MEDIA_LOADER_PEER_VERSION } from '@server/initializers/constants'
8import { storeHLSFile, storeWebTorrentFile } from '@server/lib/object-storage' 8import { storeHLSFile, storeWebTorrentFile } from '@server/lib/object-storage'
9import { getHLSDirectory, getHlsResolutionPlaylistFilename } from '@server/lib/paths' 9import { getHLSDirectory, getHlsResolutionPlaylistFilename } from '@server/lib/paths'
10import { moveToNextState } from '@server/lib/video-state' 10import { moveToFailedMoveToObjectStorageState, moveToNextState } from '@server/lib/video-state'
11import { VideoModel } from '@server/models/video/video' 11import { VideoModel } from '@server/models/video/video'
12import { VideoJobInfoModel } from '@server/models/video/video-job-info' 12import { VideoJobInfoModel } from '@server/models/video/video-job-info'
13import { MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoWithAllFiles } from '@server/types/models' 13import { MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoWithAllFiles } from '@server/types/models'
@@ -24,18 +24,25 @@ export async function processMoveToObjectStorage (job: Job) {
24 return undefined 24 return undefined
25 } 25 }
26 26
27 if (video.VideoFiles) { 27 try {
28 await moveWebTorrentFiles(video) 28 if (video.VideoFiles) {
29 } 29 await moveWebTorrentFiles(video)
30 }
30 31
31 if (video.VideoStreamingPlaylists) { 32 if (video.VideoStreamingPlaylists) {
32 await moveHLSFiles(video) 33 await moveHLSFiles(video)
33 } 34 }
35
36 const pendingMove = await VideoJobInfoModel.decrease(video.uuid, 'pendingMove')
37 if (pendingMove === 0) {
38 logger.info('Running cleanup after moving files to object storage (video %s in job %d)', video.uuid, job.id)
39 await doAfterLastJob(video, payload.isNewVideo)
40 }
41 } catch (err) {
42 logger.error('Cannot move video %s to object storage.', video.url, { err })
34 43
35 const pendingMove = await VideoJobInfoModel.decrease(video.uuid, 'pendingMove') 44 await moveToFailedMoveToObjectStorageState(video)
36 if (pendingMove === 0) { 45 await VideoJobInfoModel.abortAllTasks(video.uuid, 'pendingMove')
37 logger.info('Running cleanup after moving files to object storage (video %s in job %d)', video.uuid, job.id)
38 await doAfterLastJob(video, payload.isNewVideo)
39 } 46 }
40 47
41 return payload.videoUUID 48 return payload.videoUUID
diff --git a/server/lib/video-state.ts b/server/lib/video-state.ts
index e420991cd..97ff540ed 100644
--- a/server/lib/video-state.ts
+++ b/server/lib/video-state.ts
@@ -4,7 +4,7 @@ import { CONFIG } from '@server/initializers/config'
4import { sequelizeTypescript } from '@server/initializers/database' 4import { sequelizeTypescript } from '@server/initializers/database'
5import { VideoModel } from '@server/models/video/video' 5import { VideoModel } from '@server/models/video/video'
6import { VideoJobInfoModel } from '@server/models/video/video-job-info' 6import { VideoJobInfoModel } from '@server/models/video/video-job-info'
7import { MVideoFullLight, MVideoUUID } from '@server/types/models' 7import { MVideo, MVideoFullLight, MVideoUUID } from '@server/types/models'
8import { VideoState } from '@shared/models' 8import { VideoState } from '@shared/models'
9import { federateVideoIfNeeded } from './activitypub/videos' 9import { federateVideoIfNeeded } from './activitypub/videos'
10import { Notifier } from './notifier' 10import { Notifier } from './notifier'
@@ -79,18 +79,25 @@ async function moveToExternalStorageState (video: MVideoFullLight, isNewVideo: b
79 } 79 }
80} 80}
81 81
82function moveToFailedTranscodingState (video: MVideoFullLight) { 82function moveToFailedTranscodingState (video: MVideo) {
83 if (video.state === VideoState.TRANSCODING_FAILED) return 83 if (video.state === VideoState.TRANSCODING_FAILED) return
84 84
85 return video.setNewState(VideoState.TRANSCODING_FAILED, false, undefined) 85 return video.setNewState(VideoState.TRANSCODING_FAILED, false, undefined)
86} 86}
87 87
88function moveToFailedMoveToObjectStorageState (video: MVideo) {
89 if (video.state === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED) return
90
91 return video.setNewState(VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED, false, undefined)
92}
93
88// --------------------------------------------------------------------------- 94// ---------------------------------------------------------------------------
89 95
90export { 96export {
91 buildNextVideoState, 97 buildNextVideoState,
92 moveToExternalStorageState, 98 moveToExternalStorageState,
93 moveToFailedTranscodingState, 99 moveToFailedTranscodingState,
100 moveToFailedMoveToObjectStorageState,
94 moveToNextState 101 moveToNextState
95} 102}
96 103
diff --git a/server/models/video/video-job-info.ts b/server/models/video/video-job-info.ts
index 6a67a214c..7497addf1 100644
--- a/server/models/video/video-job-info.ts
+++ b/server/models/video/video-job-info.ts
@@ -99,4 +99,19 @@ export class VideoJobInfoModel extends Model<Partial<AttributesOnly<VideoJobInfo
99 99
100 return pendingMove 100 return pendingMove
101 } 101 }
102
103 static async abortAllTasks (videoUUID: string, column: VideoJobInfoColumnType): Promise<void> {
104 const options = { type: QueryTypes.UPDATE as QueryTypes.UPDATE, bind: { videoUUID } }
105
106 await VideoJobInfoModel.sequelize.query(`
107 UPDATE
108 "videoJobInfo"
109 SET
110 "${column}" = 0,
111 "updatedAt" = NOW()
112 FROM "video"
113 WHERE
114 "video"."id" = "videoJobInfo"."videoId" AND "video"."uuid" = $videoUUID
115 `, options)
116 }
102} 117}
diff --git a/shared/models/videos/video-state.enum.ts b/shared/models/videos/video-state.enum.ts
index 6112b6e16..09268d2ff 100644
--- a/shared/models/videos/video-state.enum.ts
+++ b/shared/models/videos/video-state.enum.ts
@@ -5,5 +5,6 @@ export const enum VideoState {
5 WAITING_FOR_LIVE = 4, 5 WAITING_FOR_LIVE = 4,
6 LIVE_ENDED = 5, 6 LIVE_ENDED = 5,
7 TO_MOVE_TO_EXTERNAL_STORAGE = 6, 7 TO_MOVE_TO_EXTERNAL_STORAGE = 6,
8 TRANSCODING_FAILED = 7 8 TRANSCODING_FAILED = 7,
9 TO_MOVE_TO_EXTERNAL_STORAGE_FAILED = 8
9} 10}