Skip to content

Commit

Permalink
add video-upload-tmp-folder-cleaner job
Browse files Browse the repository at this point in the history
  • Loading branch information
kontrollanten authored and rigelk committed Apr 20, 2021
1 parent 41b789a commit 1952fa1
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 11 deletions.
1 change: 1 addition & 0 deletions client/src/app/+admin/system/jobs/jobs.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class JobsComponent extends RestTable implements OnInit {
'video-live-ending',
'video-redundancy',
'video-transcoding',
'video-upload-tmp-folder-cleaner',
'videos-views'
]

Expand Down
2 changes: 1 addition & 1 deletion server/controllers/api/videos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ async function addVideoLegacy (req: express.Request, res: express.Response) {
async function addVideoResumable (req: express.Request, res: express.Response) {
const videoPhysicalFile = res.locals.videoFileResumable
const videoInfo: VideoCreate & { size: number} = videoPhysicalFile.metadata
const files = { bg: { path: getTmpPath(videoPhysicalFile.filename) } }
const files = { bg: { path: await getTmpPath(videoPhysicalFile.filename) } }

return addVideo(req, res, { videoPhysicalFile, videoInfo, files })
}
Expand Down
13 changes: 11 additions & 2 deletions server/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,17 @@ function getUUIDFromFilename (filename: string) {
return result[0]
}

function getTmpPath (fileId: string) {
return `/tmp/peertube-${fileId}`
let tmpPath
async function getTmpPath (filename?: string) {
if (!tmpPath) {
try {
tmpPath = join(CONFIG.STORAGE.TMP_DIR, 'resumable-uploads')
} catch (error) {
logger.error('Failed to create tmp folder.', { error })
}
}

return filename ? join(tmpPath, filename) : tmpPath
}

// ---------------------------------------------------------------------------
Expand Down
16 changes: 12 additions & 4 deletions server/initializers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ const JOB_ATTEMPTS: { [id in JobType]: number } = {
'videos-views': 1,
'activitypub-refresher': 1,
'video-redundancy': 1,
'video-live-ending': 1
'video-live-ending': 1,
'video-upload-tmp-folder-cleaner': 1
}
// Excluded keys are jobs that can be configured by admins
const JOB_CONCURRENCY: { [id in Exclude<JobType, 'video-transcoding' | 'video-import'>]: number } = {
Expand All @@ -161,7 +162,8 @@ const JOB_CONCURRENCY: { [id in Exclude<JobType, 'video-transcoding' | 'video-im
'videos-views': 1,
'activitypub-refresher': 1,
'video-redundancy': 1,
'video-live-ending': 10
'video-live-ending': 10,
'video-upload-tmp-folder-cleaner': 1
}
const JOB_TTL: { [id in JobType]: number } = {
'activitypub-http-broadcast': 60000 * 10, // 10 minutes
Expand All @@ -177,14 +179,18 @@ const JOB_TTL: { [id in JobType]: number } = {
'videos-views': undefined, // Unlimited
'activitypub-refresher': 60000 * 10, // 10 minutes
'video-redundancy': 1000 * 3600 * 3, // 3 hours
'video-live-ending': 1000 * 60 * 10 // 10 minutes
'video-live-ending': 1000 * 60 * 10, // 10 minutes
'video-upload-tmp-folder-cleaner': 60000 // 1 minute
}
const REPEAT_JOBS: { [ id: string ]: EveryRepeatOptions | CronRepeatOptions } = {
'videos-views': {
cron: randomInt(1, 20) + ' * * * *' // Between 1-20 minutes past the hour
},
'activitypub-cleaner': {
cron: '30 5 * * ' + randomInt(0, 7) // 1 time per week (random day) at 5:30 AM
},
'video-upload-tmp-folder-cleaner': {
cron: randomInt(30, 40) + ' * * * *' // Between 30-40 minutes past the hour
}
}
const JOB_PRIORITY = {
Expand All @@ -211,7 +217,8 @@ const SCHEDULER_INTERVALS_MS = {
autoFollowIndexInstances: 60000 * 60 * 24, // 1 day
removeOldViews: 60000 * 60 * 24, // 1 day
removeOldHistory: 60000 * 60 * 24, // 1 day
updateInboxStats: 1000 * 60// 1 minute
updateInboxStats: 1000 * 60, // 1 minute
removeTmpVideo: 60000 * 60 // 1 hour
}

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -776,6 +783,7 @@ if (isTestInstance() === true) {
SCHEDULER_INTERVALS_MS.checkPeerTubeVersion = 2000
REPEAT_JOBS['videos-views'] = { every: 5000 }
REPEAT_JOBS['activitypub-cleaner'] = { every: 5000 }
REPEAT_JOBS['video-upload-tmp-folder-cleaner'] = { every: 5000 }

REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1

Expand Down
53 changes: 53 additions & 0 deletions server/lib/job-queue/handlers/video-upload-tmp-folder-cleaner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { readdir, unlink, stat } from 'fs-extra'
import { Stats } from 'node:fs'
import * as path from 'path'
import { logger } from '@server/helpers/logger'
import { getTmpPath } from '@server/helpers/utils'
import { SCHEDULER_INTERVALS_MS } from '@server/initializers/constants'

async function processVideoUploadTmpFolderCleaner () {
const tmpPath = await getTmpPath()
let files: string[]

logger.debug('processVideoUploadTmpFolderCleaner: Reading files from path %s', tmpPath)

try {
files = await readdir(tmpPath)
} catch (error) {
logger.error('Failed to read resumable video upload tmp folder.', { error })
return
}

logger.debug('processVideoUploadTmpFolderCleaner: Found %d files', files.length)

await Promise.all(files.map(async function (file) {
const filePath = path.join(tmpPath, file)
let statResult: Stats

try {
statResult = await stat(filePath)
} catch (error) {
logger.error(`Failed to run stat for ${filePath}`, { error })
return
}

// current time (in miliseconds):
const now = new Date().getTime()
// time of last status change, plus 1h (in miliseconds):
const endTime = new Date(statResult.ctime).getTime() + SCHEDULER_INTERVALS_MS.removeTmpVideo

if (now > endTime) {
try {
await unlink(filePath)
} catch (error) {
logger.error(`Failed to unlink ${filePath}`, { error })
}
}
}))
}

// ---------------------------------------------------------------------------

export {
processVideoUploadTmpFolderCleaner
}
12 changes: 10 additions & 2 deletions server/lib/job-queue/job-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { processVideoImport } from './handlers/video-import'
import { processVideoLiveEnding } from './handlers/video-live-ending'
import { processVideoTranscoding } from './handlers/video-transcoding'
import { processVideosViews } from './handlers/video-views'
import { processVideoUploadTmpFolderCleaner } from './handlers/video-upload-tmp-folder-cleaner'

type CreateJobArgument =
{ type: 'activitypub-http-broadcast', payload: ActivitypubHttpBroadcastPayload } |
Expand All @@ -49,7 +50,8 @@ type CreateJobArgument =
{ type: 'videos-views', payload: {} } |
{ type: 'video-live-ending', payload: VideoLiveEndingPayload } |
{ type: 'actor-keys', payload: ActorKeysPayload } |
{ type: 'video-redundancy', payload: VideoRedundancyPayload }
{ type: 'video-redundancy', payload: VideoRedundancyPayload } |
{ type: 'video-upload-tmp-folder-cleaner', payload: { }}

type CreateJobOptions = {
delay?: number
Expand All @@ -70,7 +72,8 @@ const handlers: { [id in JobType]: (job: Bull.Job) => Promise<any> } = {
'activitypub-refresher': refreshAPObject,
'video-live-ending': processVideoLiveEnding,
'actor-keys': processActorKeys,
'video-redundancy': processVideoRedundancy
'video-redundancy': processVideoRedundancy,
'video-upload-tmp-folder-cleaner': processVideoUploadTmpFolderCleaner
}

const jobTypes: JobType[] = [
Expand All @@ -86,6 +89,7 @@ const jobTypes: JobType[] = [
'videos-views',
'activitypub-refresher',
'video-redundancy',
'video-upload-tmp-folder-cleaner',
'actor-keys',
'video-live-ending'
]
Expand Down Expand Up @@ -238,6 +242,10 @@ class JobQueue {
repeat: REPEAT_JOBS['videos-views']
}).catch(err => logger.error('Cannot add repeatable job.', { err }))

this.queues['video-upload-tmp-folder-cleaner'].add({}, {
repeat: REPEAT_JOBS['video-upload-tmp-folder-cleaner']
}).catch(err => logger.error('Cannot add repeatable job.', { err }))

if (CONFIG.FEDERATION.VIDEOS.CLEANUP_REMOTE_INTERACTIONS) {
this.queues['activitypub-cleaner'].add({}, {
repeat: REPEAT_JOBS['activitypub-cleaner']
Expand Down
2 changes: 1 addition & 1 deletion server/middlewares/validators/videos/videos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ const videosAddResumableValidator = getCommonVideoEditAttributes().concat([
const filename = `${file.id}-${uuidv4()}`
file.filename = filename
try {
await move(file.path, getTmpPath(filename))
await move(file.path, await getTmpPath(filename))
} catch (err) {
logger.error("Couldn't save incoming file", { err })
return res.status(HttpStatusCode.INTERNAL_SERVER_ERROR_500).json({ error: "Couldn't save the file." })
Expand Down
2 changes: 1 addition & 1 deletion shared/extra-utils/server/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async function waitJobs (serversArg: ServerInfo[] | ServerInfo) {
else servers = serversArg as ServerInfo[]

const states: JobState[] = [ 'waiting', 'active', 'delayed' ]
const repeatableJobs = [ 'videos-views', 'activitypub-cleaner' ]
const repeatableJobs = [ 'videos-views', 'activitypub-cleaner', 'video-upload-tmp-folder-cleaner' ]
let pendingRequests: boolean

function tasksBuilder () {
Expand Down
1 change: 1 addition & 0 deletions shared/models/server/job.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type JobType =
| 'activitypub-refresher'
| 'video-redundancy'
| 'video-live-ending'
| 'video-upload-tmp-folder-cleaner'
| 'actor-keys'

export interface Job {
Expand Down
2 changes: 2 additions & 0 deletions support/doc/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4064,6 +4064,7 @@ components:
- activitypub-refresher
- video-redundancy
- video-live-ending
- video-upload-tmp-folder-cleaner
securitySchemes:
OAuth2:
description: >
Expand Down Expand Up @@ -5214,6 +5215,7 @@ components:
- videos-views
- activitypub-refresher
- video-redundancy
- video-upload-tmp-folder-cleaner
data:
type: object
additionalProperties: true
Expand Down

0 comments on commit 1952fa1

Please sign in to comment.