Force stop remote live transcoding
This commit is contained in:
parent
f3bc1b5416
commit
17ecdf61ce
|
@ -34,6 +34,8 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
|
|
||||||
constructor (private readonly options: ProcessOptions<RunnerJobLiveRTMPHLSTranscodingPayload>) {
|
constructor (private readonly options: ProcessOptions<RunnerJobLiveRTMPHLSTranscodingPayload>) {
|
||||||
this.outputPath = join(ConfigManager.Instance.getTranscodingDirectory(), buildUUID())
|
this.outputPath = join(ConfigManager.Instance.getTranscodingDirectory(), buildUUID())
|
||||||
|
|
||||||
|
logger.debug(`Using ${this.outputPath} to process live rtmp hls transcoding job ${options.job.uuid}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
process () {
|
process () {
|
||||||
|
@ -289,6 +291,7 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (currentTry >= 3) throw err
|
if (currentTry >= 3) throw err
|
||||||
|
if ((err.res?.body as PeerTubeProblemDocument)?.code === ServerErrorCode.RUNNER_JOB_NOT_IN_PROCESSING_STATE) throw err
|
||||||
|
|
||||||
logger.warn({ err }, 'Will retry update after error')
|
logger.warn({ err }, 'Will retry update after error')
|
||||||
await wait(250)
|
await wait(250)
|
||||||
|
@ -310,6 +313,8 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
private cleanup () {
|
private cleanup () {
|
||||||
|
logger.debug(`Cleaning up job ${this.options.job.uuid}`)
|
||||||
|
|
||||||
for (const fsWatcher of this.fsWatchers) {
|
for (const fsWatcher of this.fsWatchers) {
|
||||||
fsWatcher.close()
|
fsWatcher.close()
|
||||||
.catch(err => logger.error({ err }, 'Cannot close watcher'))
|
.catch(err => logger.error({ err }, 'Cannot close watcher'))
|
||||||
|
|
|
@ -178,6 +178,10 @@ class LiveManager {
|
||||||
return !!this.rtmpServer
|
return !!this.rtmpServer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasSession (sessionId: string) {
|
||||||
|
return this.getContext().sessions.has(sessionId)
|
||||||
|
}
|
||||||
|
|
||||||
stopSessionOf (videoUUID: string, error: LiveVideoError | null) {
|
stopSessionOf (videoUUID: string, error: LiveVideoError | null) {
|
||||||
const sessionId = this.videoSessions.get(videoUUID)
|
const sessionId = this.videoSessions.get(videoUUID)
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
|
|
|
@ -477,6 +477,7 @@ class MuxingSession extends EventEmitter {
|
||||||
|
|
||||||
lTags: this.lTags,
|
lTags: this.lTags,
|
||||||
|
|
||||||
|
sessionId: this.sessionId,
|
||||||
inputLocalUrl: this.inputLocalUrl,
|
inputLocalUrl: this.inputLocalUrl,
|
||||||
inputPublicUrl: this.inputPublicUrl,
|
inputPublicUrl: this.inputPublicUrl,
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ interface AbstractTranscodingWrapperOptions {
|
||||||
|
|
||||||
lTags: LoggerTagsFn
|
lTags: LoggerTagsFn
|
||||||
|
|
||||||
|
sessionId: string
|
||||||
inputLocalUrl: string
|
inputLocalUrl: string
|
||||||
inputPublicUrl: string
|
inputPublicUrl: string
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ abstract class AbstractTranscodingWrapper extends EventEmitter {
|
||||||
fps: number
|
fps: number
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
|
protected readonly sessionId: string
|
||||||
protected readonly inputLocalUrl: string
|
protected readonly inputLocalUrl: string
|
||||||
protected readonly inputPublicUrl: string
|
protected readonly inputPublicUrl: string
|
||||||
|
|
||||||
|
@ -80,6 +82,7 @@ abstract class AbstractTranscodingWrapper extends EventEmitter {
|
||||||
this.videoUUID = options.videoLive.Video.uuid
|
this.videoUUID = options.videoLive.Video.uuid
|
||||||
this.streamingPlaylist = options.streamingPlaylist
|
this.streamingPlaylist = options.streamingPlaylist
|
||||||
|
|
||||||
|
this.sessionId = options.sessionId
|
||||||
this.inputLocalUrl = options.inputLocalUrl
|
this.inputLocalUrl = options.inputLocalUrl
|
||||||
this.inputPublicUrl = options.inputPublicUrl
|
this.inputPublicUrl = options.inputPublicUrl
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ export class RemoteTranscodingWrapper extends AbstractTranscodingWrapper {
|
||||||
async run () {
|
async run () {
|
||||||
await new LiveRTMPHLSTranscodingJobHandler().create({
|
await new LiveRTMPHLSTranscodingJobHandler().create({
|
||||||
rtmpUrl: this.inputPublicUrl,
|
rtmpUrl: this.inputPublicUrl,
|
||||||
|
sessionId: this.sessionId,
|
||||||
toTranscode: this.toTranscode,
|
toTranscode: this.toTranscode,
|
||||||
video: this.videoLive.Video,
|
video: this.videoLive.Video,
|
||||||
outputDirectory: this.outDirectory,
|
outputDirectory: this.outDirectory,
|
||||||
|
|
|
@ -20,6 +20,7 @@ type CreateOptions = {
|
||||||
video: MVideo
|
video: MVideo
|
||||||
playlist: MStreamingPlaylist
|
playlist: MStreamingPlaylist
|
||||||
|
|
||||||
|
sessionId: string
|
||||||
rtmpUrl: string
|
rtmpUrl: string
|
||||||
|
|
||||||
toTranscode: {
|
toTranscode: {
|
||||||
|
@ -37,7 +38,7 @@ type CreateOptions = {
|
||||||
export class LiveRTMPHLSTranscodingJobHandler extends AbstractJobHandler<CreateOptions, LiveRTMPHLSTranscodingUpdatePayload, LiveRTMPHLSTranscodingSuccess> {
|
export class LiveRTMPHLSTranscodingJobHandler extends AbstractJobHandler<CreateOptions, LiveRTMPHLSTranscodingUpdatePayload, LiveRTMPHLSTranscodingSuccess> {
|
||||||
|
|
||||||
async create (options: CreateOptions) {
|
async create (options: CreateOptions) {
|
||||||
const { video, rtmpUrl, toTranscode, playlist, segmentDuration, segmentListSize, outputDirectory } = options
|
const { video, rtmpUrl, toTranscode, playlist, segmentDuration, segmentListSize, outputDirectory, sessionId } = options
|
||||||
|
|
||||||
const jobUUID = buildUUID()
|
const jobUUID = buildUUID()
|
||||||
const payload: RunnerJobLiveRTMPHLSTranscodingPayload = {
|
const payload: RunnerJobLiveRTMPHLSTranscodingPayload = {
|
||||||
|
@ -54,6 +55,7 @@ export class LiveRTMPHLSTranscodingJobHandler extends AbstractJobHandler<CreateO
|
||||||
const privatePayload: RunnerJobLiveRTMPHLSTranscodingPrivatePayload = {
|
const privatePayload: RunnerJobLiveRTMPHLSTranscodingPrivatePayload = {
|
||||||
videoUUID: video.uuid,
|
videoUUID: video.uuid,
|
||||||
masterPlaylistName: playlist.playlistFilename,
|
masterPlaylistName: playlist.playlistFilename,
|
||||||
|
sessionId,
|
||||||
outputDirectory
|
outputDirectory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,16 @@ import {
|
||||||
} from '@server/helpers/custom-validators/runners/jobs'
|
} from '@server/helpers/custom-validators/runners/jobs'
|
||||||
import { isRunnerTokenValid } from '@server/helpers/custom-validators/runners/runners'
|
import { isRunnerTokenValid } from '@server/helpers/custom-validators/runners/runners'
|
||||||
import { cleanUpReqFiles } from '@server/helpers/express-utils'
|
import { cleanUpReqFiles } from '@server/helpers/express-utils'
|
||||||
|
import { LiveManager } from '@server/lib/live'
|
||||||
import { RunnerJobModel } from '@server/models/runner/runner-job'
|
import { RunnerJobModel } from '@server/models/runner/runner-job'
|
||||||
import { HttpStatusCode, RunnerJobState, RunnerJobSuccessBody, RunnerJobUpdateBody, ServerErrorCode } from '@shared/models'
|
import {
|
||||||
|
HttpStatusCode,
|
||||||
|
RunnerJobLiveRTMPHLSTranscodingPrivatePayload,
|
||||||
|
RunnerJobState,
|
||||||
|
RunnerJobSuccessBody,
|
||||||
|
RunnerJobUpdateBody,
|
||||||
|
ServerErrorCode
|
||||||
|
} from '@shared/models'
|
||||||
import { areValidationErrors } from '../shared'
|
import { areValidationErrors } from '../shared'
|
||||||
|
|
||||||
const tags = [ 'runner' ]
|
const tags = [ 'runner' ]
|
||||||
|
@ -48,8 +56,9 @@ export const updateRunnerJobValidator = [
|
||||||
if (areValidationErrors(req, res, { tags })) return cleanUpReqFiles(req)
|
if (areValidationErrors(req, res, { tags })) return cleanUpReqFiles(req)
|
||||||
|
|
||||||
const body = req.body as RunnerJobUpdateBody
|
const body = req.body as RunnerJobUpdateBody
|
||||||
|
const job = res.locals.runnerJob
|
||||||
|
|
||||||
if (isRunnerJobUpdatePayloadValid(body.payload, res.locals.runnerJob.type, req.files) !== true) {
|
if (isRunnerJobUpdatePayloadValid(body.payload, job.type, req.files) !== true) {
|
||||||
cleanUpReqFiles(req)
|
cleanUpReqFiles(req)
|
||||||
|
|
||||||
return res.fail({
|
return res.fail({
|
||||||
|
@ -59,6 +68,20 @@ export const updateRunnerJobValidator = [
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res.locals.runnerJob.type === 'live-rtmp-hls-transcoding') {
|
||||||
|
const privatePayload = job.privatePayload as RunnerJobLiveRTMPHLSTranscodingPrivatePayload
|
||||||
|
|
||||||
|
if (!LiveManager.Instance.hasSession(privatePayload.sessionId)) {
|
||||||
|
cleanUpReqFiles(req)
|
||||||
|
|
||||||
|
return res.fail({
|
||||||
|
status: HttpStatusCode.BAD_REQUEST_400,
|
||||||
|
message: 'Session of this live ended',
|
||||||
|
tags
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -197,7 +197,7 @@ describe('Test live constraints', function () {
|
||||||
live: {
|
live: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
allowReplay: true,
|
allowReplay: true,
|
||||||
maxDuration: 1,
|
maxDuration: 3,
|
||||||
transcoding: {
|
transcoding: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
resolutions: ConfigCommand.getCustomConfigResolutions(true)
|
resolutions: ConfigCommand.getCustomConfigResolutions(true)
|
||||||
|
|
|
@ -525,7 +525,7 @@ describe('Test videos search', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should search by live', async function () {
|
it('Should search by live', async function () {
|
||||||
this.timeout(60000)
|
this.timeout(120000)
|
||||||
|
|
||||||
{
|
{
|
||||||
const newConfig = {
|
const newConfig = {
|
||||||
|
|
|
@ -34,6 +34,7 @@ export interface RunnerJobLiveRTMPHLSTranscodingPrivatePayload {
|
||||||
videoUUID: string
|
videoUUID: string
|
||||||
masterPlaylistName: string
|
masterPlaylistName: string
|
||||||
outputDirectory: string
|
outputDirectory: string
|
||||||
|
sessionId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue
Block a user