diff options
-rw-r--r-- | server/lib/redundancy.ts | 11 | ||||
-rw-r--r-- | server/lib/schedulers/videos-redundancy-scheduler.ts | 54 | ||||
-rw-r--r-- | server/models/redundancy/video-redundancy.ts | 9 |
3 files changed, 51 insertions, 23 deletions
diff --git a/server/lib/redundancy.ts b/server/lib/redundancy.ts index 2a9241249..2613d01be 100644 --- a/server/lib/redundancy.ts +++ b/server/lib/redundancy.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { logger } from '@server/helpers/logger' | 2 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
3 | import { CONFIG } from '@server/initializers/config' | 3 | import { CONFIG } from '@server/initializers/config' |
4 | import { ActorFollowModel } from '@server/models/actor/actor-follow' | 4 | import { ActorFollowModel } from '@server/models/actor/actor-follow' |
5 | import { getServerActor } from '@server/models/application/application' | 5 | import { getServerActor } from '@server/models/application/application' |
@@ -8,6 +8,8 @@ import { Activity } from '@shared/models' | |||
8 | import { VideoRedundancyModel } from '../models/redundancy/video-redundancy' | 8 | import { VideoRedundancyModel } from '../models/redundancy/video-redundancy' |
9 | import { sendUndoCacheFile } from './activitypub/send' | 9 | import { sendUndoCacheFile } from './activitypub/send' |
10 | 10 | ||
11 | const lTags = loggerTagsFactory('redundancy') | ||
12 | |||
11 | async function removeVideoRedundancy (videoRedundancy: MVideoRedundancyVideo, t?: Transaction) { | 13 | async function removeVideoRedundancy (videoRedundancy: MVideoRedundancyVideo, t?: Transaction) { |
12 | const serverActor = await getServerActor() | 14 | const serverActor = await getServerActor() |
13 | 15 | ||
@@ -28,7 +30,7 @@ async function removeRedundanciesOfServer (serverId: number) { | |||
28 | async function isRedundancyAccepted (activity: Activity, byActor: MActorSignature) { | 30 | async function isRedundancyAccepted (activity: Activity, byActor: MActorSignature) { |
29 | const configAcceptFrom = CONFIG.REMOTE_REDUNDANCY.VIDEOS.ACCEPT_FROM | 31 | const configAcceptFrom = CONFIG.REMOTE_REDUNDANCY.VIDEOS.ACCEPT_FROM |
30 | if (configAcceptFrom === 'nobody') { | 32 | if (configAcceptFrom === 'nobody') { |
31 | logger.info('Do not accept remote redundancy %s due instance accept policy.', activity.id) | 33 | logger.info('Do not accept remote redundancy %s due instance accept policy.', activity.id, lTags()) |
32 | return false | 34 | return false |
33 | } | 35 | } |
34 | 36 | ||
@@ -37,7 +39,10 @@ async function isRedundancyAccepted (activity: Activity, byActor: MActorSignatur | |||
37 | const allowed = await ActorFollowModel.isFollowedBy(byActor.id, serverActor.id) | 39 | const allowed = await ActorFollowModel.isFollowedBy(byActor.id, serverActor.id) |
38 | 40 | ||
39 | if (allowed !== true) { | 41 | if (allowed !== true) { |
40 | logger.info('Do not accept remote redundancy %s because actor %s is not followed by our instance.', activity.id, byActor.url) | 42 | logger.info( |
43 | 'Do not accept remote redundancy %s because actor %s is not followed by our instance.', | ||
44 | activity.id, byActor.url, lTags() | ||
45 | ) | ||
41 | return false | 46 | return false |
42 | } | 47 | } |
43 | } | 48 | } |
diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index ebfd015b5..d9988157d 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts | |||
@@ -14,7 +14,7 @@ import { | |||
14 | MVideoWithAllFiles | 14 | MVideoWithAllFiles |
15 | } from '@server/types/models' | 15 | } from '@server/types/models' |
16 | import { VideosRedundancyStrategy } from '../../../shared/models/redundancy' | 16 | import { VideosRedundancyStrategy } from '../../../shared/models/redundancy' |
17 | import { logger } from '../../helpers/logger' | 17 | import { logger, loggerTagsFactory } from '../../helpers/logger' |
18 | import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' | 18 | import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' |
19 | import { CONFIG } from '../../initializers/config' | 19 | import { CONFIG } from '../../initializers/config' |
20 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT } from '../../initializers/constants' | 20 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT } from '../../initializers/constants' |
@@ -27,6 +27,8 @@ import { removeVideoRedundancy } from '../redundancy' | |||
27 | import { generateHLSRedundancyUrl, generateWebTorrentRedundancyUrl } from '../video-urls' | 27 | import { generateHLSRedundancyUrl, generateWebTorrentRedundancyUrl } from '../video-urls' |
28 | import { AbstractScheduler } from './abstract-scheduler' | 28 | import { AbstractScheduler } from './abstract-scheduler' |
29 | 29 | ||
30 | const lTags = loggerTagsFactory('redundancy') | ||
31 | |||
30 | type CandidateToDuplicate = { | 32 | type CandidateToDuplicate = { |
31 | redundancy: VideosRedundancyStrategy | 33 | redundancy: VideosRedundancyStrategy |
32 | video: MVideoWithAllFiles | 34 | video: MVideoWithAllFiles |
@@ -54,7 +56,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
54 | const videoToDuplicate = await VideoModel.loadWithFiles(videoId) | 56 | const videoToDuplicate = await VideoModel.loadWithFiles(videoId) |
55 | 57 | ||
56 | if (!videoToDuplicate) { | 58 | if (!videoToDuplicate) { |
57 | logger.warn('Video to manually duplicate %d does not exist anymore.', videoId) | 59 | logger.warn('Video to manually duplicate %d does not exist anymore.', videoId, lTags()) |
58 | return | 60 | return |
59 | } | 61 | } |
60 | 62 | ||
@@ -68,7 +70,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
68 | 70 | ||
69 | protected async internalExecute () { | 71 | protected async internalExecute () { |
70 | for (const redundancyConfig of CONFIG.REDUNDANCY.VIDEOS.STRATEGIES) { | 72 | for (const redundancyConfig of CONFIG.REDUNDANCY.VIDEOS.STRATEGIES) { |
71 | logger.info('Running redundancy scheduler for strategy %s.', redundancyConfig.strategy) | 73 | logger.info('Running redundancy scheduler for strategy %s.', redundancyConfig.strategy, lTags()) |
72 | 74 | ||
73 | try { | 75 | try { |
74 | const videoToDuplicate = await this.findVideoToDuplicate(redundancyConfig) | 76 | const videoToDuplicate = await this.findVideoToDuplicate(redundancyConfig) |
@@ -84,15 +86,18 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
84 | await this.purgeCacheIfNeeded(candidateToDuplicate) | 86 | await this.purgeCacheIfNeeded(candidateToDuplicate) |
85 | 87 | ||
86 | if (await this.isTooHeavy(candidateToDuplicate)) { | 88 | if (await this.isTooHeavy(candidateToDuplicate)) { |
87 | logger.info('Video %s is too big for our cache, skipping.', videoToDuplicate.url) | 89 | logger.info('Video %s is too big for our cache, skipping.', videoToDuplicate.url, lTags(videoToDuplicate.uuid)) |
88 | continue | 90 | continue |
89 | } | 91 | } |
90 | 92 | ||
91 | logger.info('Will duplicate video %s in redundancy scheduler "%s".', videoToDuplicate.url, redundancyConfig.strategy) | 93 | logger.info( |
94 | 'Will duplicate video %s in redundancy scheduler "%s".', | ||
95 | videoToDuplicate.url, redundancyConfig.strategy, lTags(videoToDuplicate.uuid) | ||
96 | ) | ||
92 | 97 | ||
93 | await this.createVideoRedundancies(candidateToDuplicate) | 98 | await this.createVideoRedundancies(candidateToDuplicate) |
94 | } catch (err) { | 99 | } catch (err) { |
95 | logger.error('Cannot run videos redundancy %s.', redundancyConfig.strategy, { err }) | 100 | logger.error('Cannot run videos redundancy %s.', redundancyConfig.strategy, { err, ...lTags() }) |
96 | } | 101 | } |
97 | } | 102 | } |
98 | 103 | ||
@@ -120,15 +125,19 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
120 | 125 | ||
121 | // If the administrator disabled the redundancy or decreased the cache size, remove this redundancy instead of extending it | 126 | // If the administrator disabled the redundancy or decreased the cache size, remove this redundancy instead of extending it |
122 | if (!redundancyConfig || await this.isTooHeavy(candidate)) { | 127 | if (!redundancyConfig || await this.isTooHeavy(candidate)) { |
123 | logger.info('Destroying redundancy %s because the cache size %s is too heavy.', redundancyModel.url, redundancyModel.strategy) | 128 | logger.info( |
129 | 'Destroying redundancy %s because the cache size %s is too heavy.', | ||
130 | redundancyModel.url, redundancyModel.strategy, lTags(candidate.video.uuid) | ||
131 | ) | ||
132 | |||
124 | await removeVideoRedundancy(redundancyModel) | 133 | await removeVideoRedundancy(redundancyModel) |
125 | } else { | 134 | } else { |
126 | await this.extendsRedundancy(redundancyModel) | 135 | await this.extendsRedundancy(redundancyModel) |
127 | } | 136 | } |
128 | } catch (err) { | 137 | } catch (err) { |
129 | logger.error( | 138 | logger.error( |
130 | 'Cannot extend or remove expiration of %s video from our redundancy system.', this.buildEntryLogId(redundancyModel), | 139 | 'Cannot extend or remove expiration of %s video from our redundancy system.', |
131 | { err } | 140 | this.buildEntryLogId(redundancyModel), { err, ...lTags(redundancyModel.getVideoUUID()) } |
132 | ) | 141 | ) |
133 | } | 142 | } |
134 | } | 143 | } |
@@ -152,7 +161,10 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
152 | try { | 161 | try { |
153 | await removeVideoRedundancy(redundancyModel) | 162 | await removeVideoRedundancy(redundancyModel) |
154 | } catch (err) { | 163 | } catch (err) { |
155 | logger.error('Cannot remove redundancy %s from our redundancy system.', this.buildEntryLogId(redundancyModel)) | 164 | logger.error( |
165 | 'Cannot remove redundancy %s from our redundancy system.', | ||
166 | this.buildEntryLogId(redundancyModel), lTags(redundancyModel.getVideoUUID()) | ||
167 | ) | ||
156 | } | 168 | } |
157 | } | 169 | } |
158 | } | 170 | } |
@@ -176,7 +188,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
176 | const video = await this.loadAndRefreshVideo(data.video.url) | 188 | const video = await this.loadAndRefreshVideo(data.video.url) |
177 | 189 | ||
178 | if (!video) { | 190 | if (!video) { |
179 | logger.info('Video %s we want to duplicate does not existing anymore, skipping.', data.video.url) | 191 | logger.info('Video %s we want to duplicate does not existing anymore, skipping.', data.video.url, lTags(data.video.uuid)) |
180 | 192 | ||
181 | return | 193 | return |
182 | } | 194 | } |
@@ -218,7 +230,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
218 | 230 | ||
219 | const serverActor = await getServerActor() | 231 | const serverActor = await getServerActor() |
220 | 232 | ||
221 | logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, strategy) | 233 | logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, strategy, lTags(video.uuid)) |
222 | 234 | ||
223 | const trackerUrls = await TrackerModel.listUrlsByVideoId(video.id) | 235 | const trackerUrls = await TrackerModel.listUrlsByVideoId(video.id) |
224 | const magnetUri = generateMagnetUri(video, file, trackerUrls) | 236 | const magnetUri = generateMagnetUri(video, file, trackerUrls) |
@@ -241,7 +253,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
241 | 253 | ||
242 | await sendCreateCacheFile(serverActor, video, createdModel) | 254 | await sendCreateCacheFile(serverActor, video, createdModel) |
243 | 255 | ||
244 | logger.info('Duplicated %s - %d -> %s.', video.url, file.resolution, createdModel.url) | 256 | logger.info('Duplicated %s - %d -> %s.', video.url, file.resolution, createdModel.url, lTags(video.uuid)) |
245 | } | 257 | } |
246 | 258 | ||
247 | private async createStreamingPlaylistRedundancy ( | 259 | private async createStreamingPlaylistRedundancy ( |
@@ -260,7 +272,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
260 | const playlist = Object.assign(playlistArg, { Video: video }) | 272 | const playlist = Object.assign(playlistArg, { Video: video }) |
261 | const serverActor = await getServerActor() | 273 | const serverActor = await getServerActor() |
262 | 274 | ||
263 | logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, strategy) | 275 | logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, strategy, lTags(video.uuid)) |
264 | 276 | ||
265 | const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) | 277 | const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) |
266 | const masterPlaylistUrl = playlist.getMasterPlaylistUrl(video) | 278 | const masterPlaylistUrl = playlist.getMasterPlaylistUrl(video) |
@@ -282,11 +294,11 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
282 | 294 | ||
283 | await sendCreateCacheFile(serverActor, video, createdModel) | 295 | await sendCreateCacheFile(serverActor, video, createdModel) |
284 | 296 | ||
285 | logger.info('Duplicated playlist %s -> %s.', masterPlaylistUrl, createdModel.url) | 297 | logger.info('Duplicated playlist %s -> %s.', masterPlaylistUrl, createdModel.url, lTags(video.uuid)) |
286 | } | 298 | } |
287 | 299 | ||
288 | private async extendsExpirationOf (redundancy: MVideoRedundancyVideo, expiresAfterMs: number) { | 300 | private async extendsExpirationOf (redundancy: MVideoRedundancyVideo, expiresAfterMs: number) { |
289 | logger.info('Extending expiration of %s.', redundancy.url) | 301 | logger.info('Extending expiration of %s.', redundancy.url, lTags(redundancy.getVideoUUID())) |
290 | 302 | ||
291 | const serverActor = await getServerActor() | 303 | const serverActor = await getServerActor() |
292 | 304 | ||
@@ -317,10 +329,14 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
317 | private async isTooHeavy (candidateToDuplicate: CandidateToDuplicate) { | 329 | private async isTooHeavy (candidateToDuplicate: CandidateToDuplicate) { |
318 | const maxSize = candidateToDuplicate.redundancy.size | 330 | const maxSize = candidateToDuplicate.redundancy.size |
319 | 331 | ||
320 | const { totalUsed } = await VideoRedundancyModel.getStats(candidateToDuplicate.redundancy.strategy) | 332 | const { totalUsed: used } = await VideoRedundancyModel.getStats(candidateToDuplicate.redundancy.strategy) |
321 | const totalWillDuplicate = totalUsed + this.getTotalFileSizes(candidateToDuplicate.files, candidateToDuplicate.streamingPlaylists) | 333 | |
334 | const videoSize = this.getTotalFileSizes(candidateToDuplicate.files, candidateToDuplicate.streamingPlaylists) | ||
335 | const total = used + videoSize | ||
336 | |||
337 | logger.debug('Checking candidate size.', { used, videoSize, total, ...lTags(candidateToDuplicate.video.uuid) }) | ||
322 | 338 | ||
323 | return totalWillDuplicate > maxSize | 339 | return total > maxSize |
324 | } | 340 | } |
325 | 341 | ||
326 | private buildNewExpiration (expiresAfterMs: number) { | 342 | private buildNewExpiration (expiresAfterMs: number) { |
diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts index 44c17f8e5..529977924 100644 --- a/server/models/redundancy/video-redundancy.ts +++ b/server/models/redundancy/video-redundancy.ts | |||
@@ -411,7 +411,7 @@ export class VideoRedundancyModel extends Model<Partial<AttributesOnly<VideoRedu | |||
411 | return VideoRedundancyModel.scope([ ScopeNames.WITH_VIDEO ]).findOne(query) | 411 | return VideoRedundancyModel.scope([ ScopeNames.WITH_VIDEO ]).findOne(query) |
412 | } | 412 | } |
413 | 413 | ||
414 | static async listLocalExpired () { | 414 | static async listLocalExpired (): Promise<MVideoRedundancyVideo[]> { |
415 | const actor = await getServerActor() | 415 | const actor = await getServerActor() |
416 | 416 | ||
417 | const query = { | 417 | const query = { |
@@ -701,6 +701,13 @@ export class VideoRedundancyModel extends Model<Partial<AttributesOnly<VideoRedu | |||
701 | return undefined | 701 | return undefined |
702 | } | 702 | } |
703 | 703 | ||
704 | getVideoUUID () { | ||
705 | const video = this.getVideo() | ||
706 | if (!video) return undefined | ||
707 | |||
708 | return video.uuid | ||
709 | } | ||
710 | |||
704 | isOwned () { | 711 | isOwned () { |
705 | return !!this.strategy | 712 | return !!this.strategy |
706 | } | 713 | } |