diff options
Diffstat (limited to 'server/lib/schedulers')
4 files changed, 81 insertions, 49 deletions
diff --git a/server/lib/schedulers/plugins-check-scheduler.ts b/server/lib/schedulers/plugins-check-scheduler.ts index 06450fa01..820c01693 100644 --- a/server/lib/schedulers/plugins-check-scheduler.ts +++ b/server/lib/schedulers/plugins-check-scheduler.ts | |||
@@ -33,7 +33,7 @@ export class PluginsCheckScheduler extends AbstractScheduler { | |||
33 | const chunks = chunk(plugins, 10) | 33 | const chunks = chunk(plugins, 10) |
34 | for (const chunk of chunks) { | 34 | for (const chunk of chunks) { |
35 | // Find plugins according to their npm name | 35 | // Find plugins according to their npm name |
36 | const pluginIndex: { [npmName: string]: PluginModel} = {} | 36 | const pluginIndex: { [npmName: string]: PluginModel } = {} |
37 | for (const plugin of chunk) { | 37 | for (const plugin of chunk) { |
38 | pluginIndex[PluginModel.buildNpmName(plugin.name, plugin.type)] = plugin | 38 | pluginIndex[PluginModel.buildNpmName(plugin.name, plugin.type)] = plugin |
39 | } | 39 | } |
diff --git a/server/lib/schedulers/update-videos-scheduler.ts b/server/lib/schedulers/update-videos-scheduler.ts index 5bfbc3cd2..e38685c04 100644 --- a/server/lib/schedulers/update-videos-scheduler.ts +++ b/server/lib/schedulers/update-videos-scheduler.ts | |||
@@ -1,11 +1,14 @@ | |||
1 | import { VideoModel } from '@server/models/video/video' | 1 | import { VideoModel } from '@server/models/video/video' |
2 | import { MVideoFullLight } from '@server/types/models' | 2 | import { MScheduleVideoUpdate } from '@server/types/models' |
3 | import { VideoPrivacy, VideoState } from '@shared/models' | ||
3 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
4 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' | 5 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' |
5 | import { sequelizeTypescript } from '../../initializers/database' | 6 | import { sequelizeTypescript } from '../../initializers/database' |
6 | import { ScheduleVideoUpdateModel } from '../../models/video/schedule-video-update' | 7 | import { ScheduleVideoUpdateModel } from '../../models/video/schedule-video-update' |
7 | import { federateVideoIfNeeded } from '../activitypub/videos' | ||
8 | import { Notifier } from '../notifier' | 8 | import { Notifier } from '../notifier' |
9 | import { addVideoJobsAfterUpdate } from '../video' | ||
10 | import { VideoPathManager } from '../video-path-manager' | ||
11 | import { setVideoPrivacy } from '../video-privacy' | ||
9 | import { AbstractScheduler } from './abstract-scheduler' | 12 | import { AbstractScheduler } from './abstract-scheduler' |
10 | 13 | ||
11 | export class UpdateVideosScheduler extends AbstractScheduler { | 14 | export class UpdateVideosScheduler extends AbstractScheduler { |
@@ -26,35 +29,58 @@ export class UpdateVideosScheduler extends AbstractScheduler { | |||
26 | if (!await ScheduleVideoUpdateModel.areVideosToUpdate()) return undefined | 29 | if (!await ScheduleVideoUpdateModel.areVideosToUpdate()) return undefined |
27 | 30 | ||
28 | const schedules = await ScheduleVideoUpdateModel.listVideosToUpdate() | 31 | const schedules = await ScheduleVideoUpdateModel.listVideosToUpdate() |
29 | const publishedVideos: MVideoFullLight[] = [] | ||
30 | 32 | ||
31 | for (const schedule of schedules) { | 33 | for (const schedule of schedules) { |
32 | await sequelizeTypescript.transaction(async t => { | 34 | const videoOnly = await VideoModel.load(schedule.videoId) |
33 | const video = await VideoModel.loadFull(schedule.videoId, t) | 35 | const mutexReleaser = await VideoPathManager.Instance.lockFiles(videoOnly.uuid) |
34 | 36 | ||
35 | logger.info('Executing scheduled video update on %s.', video.uuid) | 37 | try { |
38 | const { video, published } = await this.updateAVideo(schedule) | ||
36 | 39 | ||
37 | if (schedule.privacy) { | 40 | if (published) Notifier.Instance.notifyOnVideoPublishedAfterScheduledUpdate(video) |
38 | const wasConfidentialVideo = video.isConfidential() | 41 | } catch (err) { |
39 | const isNewVideo = video.isNewVideo(schedule.privacy) | 42 | logger.error('Cannot update video', { err }) |
43 | } | ||
40 | 44 | ||
41 | video.setPrivacy(schedule.privacy) | 45 | mutexReleaser() |
42 | await video.save({ transaction: t }) | 46 | } |
43 | await federateVideoIfNeeded(video, isNewVideo, t) | 47 | } |
48 | |||
49 | private async updateAVideo (schedule: MScheduleVideoUpdate) { | ||
50 | let oldPrivacy: VideoPrivacy | ||
51 | let isNewVideo: boolean | ||
52 | let published = false | ||
53 | |||
54 | const video = await sequelizeTypescript.transaction(async t => { | ||
55 | const video = await VideoModel.loadFull(schedule.videoId, t) | ||
56 | if (video.state === VideoState.TO_TRANSCODE) return null | ||
57 | |||
58 | logger.info('Executing scheduled video update on %s.', video.uuid) | ||
59 | |||
60 | if (schedule.privacy) { | ||
61 | isNewVideo = video.isNewVideo(schedule.privacy) | ||
62 | oldPrivacy = video.privacy | ||
44 | 63 | ||
45 | if (wasConfidentialVideo) { | 64 | setVideoPrivacy(video, schedule.privacy) |
46 | publishedVideos.push(video) | 65 | await video.save({ transaction: t }) |
47 | } | 66 | |
67 | if (oldPrivacy === VideoPrivacy.PRIVATE) { | ||
68 | published = true | ||
48 | } | 69 | } |
70 | } | ||
49 | 71 | ||
50 | await schedule.destroy({ transaction: t }) | 72 | await schedule.destroy({ transaction: t }) |
51 | }) | 73 | |
52 | } | 74 | return video |
75 | }) | ||
53 | 76 | ||
54 | for (const v of publishedVideos) { | 77 | if (!video) { |
55 | Notifier.Instance.notifyOnNewVideoIfNeeded(v) | 78 | return { video, published: false } |
56 | Notifier.Instance.notifyOnVideoPublishedAfterScheduledUpdate(v) | ||
57 | } | 79 | } |
80 | |||
81 | await addVideoJobsAfterUpdate({ video, oldPrivacy, isNewVideo, nameChanged: false }) | ||
82 | |||
83 | return { video, published } | ||
58 | } | 84 | } |
59 | 85 | ||
60 | static get Instance () { | 86 | static get Instance () { |
diff --git a/server/lib/schedulers/video-channel-sync-latest-scheduler.ts b/server/lib/schedulers/video-channel-sync-latest-scheduler.ts index a527f68b5..efb957fac 100644 --- a/server/lib/schedulers/video-channel-sync-latest-scheduler.ts +++ b/server/lib/schedulers/video-channel-sync-latest-scheduler.ts | |||
@@ -2,7 +2,6 @@ import { logger } from '@server/helpers/logger' | |||
2 | import { CONFIG } from '@server/initializers/config' | 2 | import { CONFIG } from '@server/initializers/config' |
3 | import { VideoChannelModel } from '@server/models/video/video-channel' | 3 | import { VideoChannelModel } from '@server/models/video/video-channel' |
4 | import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync' | 4 | import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync' |
5 | import { VideoChannelSyncState } from '@shared/models' | ||
6 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' | 5 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' |
7 | import { synchronizeChannel } from '../sync-channel' | 6 | import { synchronizeChannel } from '../sync-channel' |
8 | import { AbstractScheduler } from './abstract-scheduler' | 7 | import { AbstractScheduler } from './abstract-scheduler' |
@@ -28,26 +27,20 @@ export class VideoChannelSyncLatestScheduler extends AbstractScheduler { | |||
28 | for (const sync of channelSyncs) { | 27 | for (const sync of channelSyncs) { |
29 | const channel = await VideoChannelModel.loadAndPopulateAccount(sync.videoChannelId) | 28 | const channel = await VideoChannelModel.loadAndPopulateAccount(sync.videoChannelId) |
30 | 29 | ||
31 | try { | 30 | logger.info( |
32 | logger.info( | 31 | 'Creating video import jobs for "%s" sync with external channel "%s"', |
33 | 'Creating video import jobs for "%s" sync with external channel "%s"', | 32 | channel.Actor.preferredUsername, sync.externalChannelUrl |
34 | channel.Actor.preferredUsername, sync.externalChannelUrl | 33 | ) |
35 | ) | 34 | |
36 | 35 | const onlyAfter = sync.lastSyncAt || sync.createdAt | |
37 | const onlyAfter = sync.lastSyncAt || sync.createdAt | 36 | |
38 | 37 | await synchronizeChannel({ | |
39 | await synchronizeChannel({ | 38 | channel, |
40 | channel, | 39 | externalChannelUrl: sync.externalChannelUrl, |
41 | externalChannelUrl: sync.externalChannelUrl, | 40 | videosCountLimit: CONFIG.IMPORT.VIDEO_CHANNEL_SYNCHRONIZATION.VIDEOS_LIMIT_PER_SYNCHRONIZATION, |
42 | videosCountLimit: CONFIG.IMPORT.VIDEO_CHANNEL_SYNCHRONIZATION.VIDEOS_LIMIT_PER_SYNCHRONIZATION, | 41 | channelSync: sync, |
43 | channelSync: sync, | 42 | onlyAfter |
44 | onlyAfter | 43 | }) |
45 | }) | ||
46 | } catch (err) { | ||
47 | logger.error(`Failed to synchronize channel ${channel.Actor.preferredUsername}`, { err }) | ||
48 | sync.state = VideoChannelSyncState.FAILED | ||
49 | await sync.save() | ||
50 | } | ||
51 | } | 44 | } |
52 | } | 45 | } |
53 | 46 | ||
diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index 91c217615..dc450c338 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts | |||
@@ -16,7 +16,7 @@ import { VideosRedundancyStrategy } from '../../../shared/models/redundancy' | |||
16 | import { logger, loggerTagsFactory } from '../../helpers/logger' | 16 | import { logger, loggerTagsFactory } from '../../helpers/logger' |
17 | import { downloadWebTorrentVideo } from '../../helpers/webtorrent' | 17 | import { downloadWebTorrentVideo } from '../../helpers/webtorrent' |
18 | import { CONFIG } from '../../initializers/config' | 18 | import { CONFIG } from '../../initializers/config' |
19 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT } from '../../initializers/constants' | 19 | import { DIRECTORIES, REDUNDANCY, VIDEO_IMPORT_TIMEOUT } from '../../initializers/constants' |
20 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' | 20 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' |
21 | import { sendCreateCacheFile, sendUpdateCacheFile } from '../activitypub/send' | 21 | import { sendCreateCacheFile, sendUpdateCacheFile } from '../activitypub/send' |
22 | import { getLocalVideoCacheFileActivityPubUrl, getLocalVideoCacheStreamingPlaylistActivityPubUrl } from '../activitypub/url' | 22 | import { getLocalVideoCacheFileActivityPubUrl, getLocalVideoCacheStreamingPlaylistActivityPubUrl } from '../activitypub/url' |
@@ -115,16 +115,29 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
115 | for (const redundancyModel of expired) { | 115 | for (const redundancyModel of expired) { |
116 | try { | 116 | try { |
117 | const redundancyConfig = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.find(s => s.strategy === redundancyModel.strategy) | 117 | const redundancyConfig = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.find(s => s.strategy === redundancyModel.strategy) |
118 | |||
119 | // If the admin disabled the redundancy, remove this redundancy instead of extending it | ||
120 | if (!redundancyConfig) { | ||
121 | logger.info( | ||
122 | 'Destroying redundancy %s because the redundancy %s does not exist anymore.', | ||
123 | redundancyModel.url, redundancyModel.strategy | ||
124 | ) | ||
125 | |||
126 | await removeVideoRedundancy(redundancyModel) | ||
127 | continue | ||
128 | } | ||
129 | |||
118 | const { totalUsed } = await VideoRedundancyModel.getStats(redundancyConfig.strategy) | 130 | const { totalUsed } = await VideoRedundancyModel.getStats(redundancyConfig.strategy) |
119 | 131 | ||
120 | // If the administrator disabled the redundancy or decreased the cache size, remove this redundancy instead of extending it | 132 | // If the admin decreased the cache size, remove this redundancy instead of extending it |
121 | if (!redundancyConfig || totalUsed > redundancyConfig.size) { | 133 | if (totalUsed > redundancyConfig.size) { |
122 | logger.info('Destroying redundancy %s because the cache size %s is too heavy.', redundancyModel.url, redundancyModel.strategy) | 134 | logger.info('Destroying redundancy %s because the cache size %s is too heavy.', redundancyModel.url, redundancyModel.strategy) |
123 | 135 | ||
124 | await removeVideoRedundancy(redundancyModel) | 136 | await removeVideoRedundancy(redundancyModel) |
125 | } else { | 137 | continue |
126 | await this.extendsRedundancy(redundancyModel) | ||
127 | } | 138 | } |
139 | |||
140 | await this.extendsRedundancy(redundancyModel) | ||
128 | } catch (err) { | 141 | } catch (err) { |
129 | logger.error( | 142 | logger.error( |
130 | 'Cannot extend or remove expiration of %s video from our redundancy system.', | 143 | 'Cannot extend or remove expiration of %s video from our redundancy system.', |
@@ -262,7 +275,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
262 | 275 | ||
263 | logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, strategy, lTags(video.uuid)) | 276 | logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, strategy, lTags(video.uuid)) |
264 | 277 | ||
265 | const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) | 278 | const destDirectory = join(DIRECTORIES.HLS_REDUNDANCY, video.uuid) |
266 | const masterPlaylistUrl = playlist.getMasterPlaylistUrl(video) | 279 | const masterPlaylistUrl = playlist.getMasterPlaylistUrl(video) |
267 | 280 | ||
268 | const maxSizeKB = this.getTotalFileSizes([], [ playlist ]) / 1000 | 281 | const maxSizeKB = this.getTotalFileSizes([], [ playlist ]) / 1000 |