Skip to content

Commit 90b0859

Browse files
committed
Merge remote-tracking branch 'origin/test/release51' into fix/sofie-3626/delete-next-partInstance
2 parents 255c27c + b1045f9 commit 90b0859

File tree

8 files changed

+110
-22
lines changed

8 files changed

+110
-22
lines changed

packages/job-worker/src/ingest/commit.ts

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,13 @@ export async function CommitIngestOperation(
178178
// Ensure any adlibbed parts are updated to follow the segmentId of the previous part
179179
await updateSegmentIdsForAdlibbedPartInstances(context, ingestModel, beforePartMap)
180180

181+
// TODO: This whole section can probably be removed later, it's really unneccessary in the grand scheme of
182+
// things, it's here only to debug some problems
181183
if (data.renamedSegments && data.renamedSegments.size > 0) {
182-
logger.debug(`Renamed segments: ${JSON.stringify(Array.from(data.renamedSegments.entries()))}`)
184+
logger.verbose(`Renamed segments: ${JSON.stringify(Array.from(data.renamedSegments.entries()))}`)
183185
}
186+
// End of temporary section
187+
184188
// ensure instances have matching segmentIds with the parts
185189
await updatePartInstancesSegmentIds(context, ingestModel, data.renamedSegments, beforePartMap)
186190

@@ -220,6 +224,8 @@ export async function CommitIngestOperation(
220224
const pSaveIngest = ingestModel.saveAllToDatabase()
221225
pSaveIngest.catch(() => null) // Ensure promise isn't reported as unhandled
222226

227+
ensureNextPartInstanceIsNotDeleted(playoutModel)
228+
223229
await validateAdlibTestingSegment(context, playoutModel)
224230

225231
try {
@@ -273,14 +279,18 @@ function canRemoveSegment(
273279
logger.warn(`Not allowing removal of previous playing segment "${segmentId}", making segment unsynced instead`)
274280
return false
275281
}
276-
if (
277-
currentPartInstance?.segmentId === segmentId ||
278-
(nextPartInstance?.segmentId === segmentId && isTooCloseToAutonext(currentPartInstance, false))
279-
) {
282+
if (currentPartInstance?.segmentId === segmentId) {
280283
// Don't allow removing an active rundown
281284
logger.warn(`Not allowing removal of current playing segment "${segmentId}", making segment unsynced instead`)
282285
return false
283286
}
287+
if (nextPartInstance?.segmentId === segmentId && isTooCloseToAutonext(currentPartInstance, false)) {
288+
// Don't allow removing an active rundown
289+
logger.warn(
290+
`Not allowing removal of nexted segment "${segmentId}", because it's too close to an auto-next, making segment unsynced instead`
291+
)
292+
return false
293+
}
284294

285295
if (nextPartInstance?.segmentId === segmentId && nextPartInstance.orphaned === 'adlib-part') {
286296
// Don't allow removing an active rundown
@@ -365,6 +375,8 @@ async function updatePartInstancesSegmentIds(
365375

366376
const writeOps: AnyBulkWriteOperation<DBPartInstance>[] = []
367377

378+
logger.debug(`updatePartInstancesSegmentIds: renameRules: ${JSON.stringify(renameRules)}`)
379+
368380
for (const [newSegmentId, rule] of rulesInOrder) {
369381
if (rule.fromSegmentIds.length) {
370382
writeOps.push({
@@ -402,7 +414,12 @@ async function updatePartInstancesSegmentIds(
402414
if (writeOps.length) await context.directCollections.PartInstances.bulkWrite(writeOps)
403415

404416
// Double check that there are no parts using the old segment ids:
405-
const oldSegmentIds = Array.from(renameRules.keys())
417+
// TODO: This whole section can probably be removed later, it's really unneccessary in the grand scheme of
418+
// things, it's here only to debug some problems
419+
const oldSegmentIds: SegmentId[] = []
420+
for (const renameRule of renameRules.values()) {
421+
oldSegmentIds.push(...renameRule.fromSegmentIds)
422+
}
406423
const [badPartInstances, badParts] = await Promise.all([
407424
await context.directCollections.PartInstances.findFetch({
408425
rundownId: ingestModel.rundownId,
@@ -428,6 +445,7 @@ async function updatePartInstancesSegmentIds(
428445
)}": ${JSON.stringify(badParts)}, writeOps: ${JSON.stringify(writeOps)}`
429446
)
430447
}
448+
// End of the temporary section
431449
}
432450
}
433451

@@ -662,10 +680,27 @@ async function getSelectedPartInstances(
662680
})
663681
: []
664682

683+
const currentPartInstance = instances.find((inst) => inst._id === playlist.currentPartInfo?.partInstanceId)
684+
const nextPartInstance = instances.find((inst) => inst._id === playlist.nextPartInfo?.partInstanceId)
685+
const previousPartInstance = instances.find((inst) => inst._id === playlist.previousPartInfo?.partInstanceId)
686+
687+
if (playlist.currentPartInfo?.partInstanceId && !currentPartInstance)
688+
logger.error(
689+
`playlist.currentPartInfo is set, but PartInstance "${playlist.currentPartInfo?.partInstanceId}" was not found!`
690+
)
691+
if (playlist.nextPartInfo?.partInstanceId && !nextPartInstance)
692+
logger.error(
693+
`playlist.nextPartInfo is set, but PartInstance "${playlist.nextPartInfo?.partInstanceId}" was not found!`
694+
)
695+
if (playlist.previousPartInfo?.partInstanceId && !previousPartInstance)
696+
logger.error(
697+
`playlist.previousPartInfo is set, but PartInstance "${playlist.previousPartInfo?.partInstanceId}" was not found!`
698+
)
699+
665700
return {
666-
currentPartInstance: instances.find((inst) => inst._id === playlist.currentPartInfo?.partInstanceId),
667-
nextPartInstance: instances.find((inst) => inst._id === playlist.nextPartInfo?.partInstanceId),
668-
previousPartInstance: instances.find((inst) => inst._id === playlist.previousPartInfo?.partInstanceId),
701+
currentPartInstance,
702+
nextPartInstance,
703+
previousPartInstance,
669704
}
670705
}
671706

@@ -815,6 +850,16 @@ async function removeSegments(
815850
})
816851
}
817852
for (const segmentId of purgeSegmentIds) {
853+
logger.debug(
854+
`IngestModel: Removing segment "${segmentId}" (` +
855+
`previousPartInfo?.partInstanceId: ${newPlaylist.previousPartInfo?.partInstanceId},` +
856+
`currentPartInfo?.partInstanceId: ${newPlaylist.currentPartInfo?.partInstanceId},` +
857+
`nextPartInfo?.partInstanceId: ${newPlaylist.nextPartInfo?.partInstanceId},` +
858+
`previousPartInstance.segmentId: ${!previousPartInstance ? 'N/A' : previousPartInstance.segmentId},` +
859+
`currentPartInstance.segmentId: ${!currentPartInstance ? 'N/A' : currentPartInstance.segmentId},` +
860+
`nextPartInstance.segmentId: ${!nextPartInstance ? 'N/A' : nextPartInstance.segmentId}` +
861+
`)`
862+
)
818863
ingestModel.removeSegment(segmentId)
819864
}
820865
}
@@ -824,3 +869,12 @@ async function validateAdlibTestingSegment(_context: JobContext, playoutModel: P
824869
rundown.updateAdlibTestingSegmentRank()
825870
}
826871
}
872+
function ensureNextPartInstanceIsNotDeleted(playoutModel: PlayoutModel) {
873+
if (playoutModel.nextPartInstance) {
874+
// Check if the segment of the nextPartInstance exists
875+
if (!playoutModel.findSegment(playoutModel.nextPartInstance.partInstance.segmentId)) {
876+
// The segment doesn't exist, set nextPartInstance to null, it'll be set by ensureNextPartIsValid() later.
877+
playoutModel.setPartInstanceAsNext(null, false, false)
878+
}
879+
}
880+
}

packages/job-worker/src/ingest/lock.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ export interface CommitIngestData {
2222
removedSegmentIds: SegmentId[]
2323
/**
2424
* Segments that had their ids changed. This helps then be orphaned in the correct place
25-
* eg, whole segment is renamed and middle part deleted
26-
* Note: Only supported for MOS, not 'normal' ingest operations
25+
* eg, whole segment is renamed and middle part deleted.
26+
*
27+
* Maps fromSegmentId to toSegmentId.
28+
*
29+
* _Note: Only supported for MOS, not 'normal' ingest operations_
2730
*/
2831
renamedSegments: Map<SegmentId, SegmentId> | null
2932

packages/job-worker/src/ingest/mosDevice/diff.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { IngestSegment } from '@sofie-automation/blueprints-integration'
1111
import { SegmentOrphanedReason } from '@sofie-automation/corelib/dist/dataModel/Segment'
1212
import { CommitIngestData } from '../lock'
1313
import { IngestSegmentModel } from '../model/IngestSegmentModel'
14+
import { logger } from '../../logging'
1415

1516
/**
1617
* Update the Ids of Segments based on new Ingest data
@@ -158,9 +159,11 @@ function applyExternalIdDiff(
158159
}
159160

160161
// Remove the old Segment and it's contents, the new one will be generated shortly
162+
logger.debug(`applyExternalIdDiff: Marking Segment for removing "${oldSegmentId}"`)
161163
ingestModel.removeSegment(oldSegmentId)
162164
} else {
163165
// Perform the rename
166+
logger.debug(`applyExternalIdDiff: Marking Segment for renaming "${oldSegmentId}" -> "${newSegmentId}"`)
164167
ingestModel.changeSegmentId(oldSegmentId, newSegmentId)
165168
}
166169
}

packages/job-worker/src/ingest/syncChangesToPartInstance.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { validateAdlibTestingPartInstanceProperties } from '../playout/adlibTest
3333
import { ReadonlyDeep } from 'type-fest'
3434
import { convertIngestModelToPlayoutRundownWithSegments } from './commit'
3535
import { PlayoutRundownModel } from '../playout/model/PlayoutRundownModel'
36+
import { PieceInstance } from '@sofie-automation/corelib/dist/dataModel/PieceInstance'
3637

3738
type PlayStatus = 'previous' | 'current' | 'next'
3839
type SyncedInstance = {
@@ -143,15 +144,29 @@ export async function syncChangesToPartInstances(
143144
if (!playoutRundownModelForPart)
144145
throw new Error(`Internal Error: playoutRundownModelForPart is undefined (it should never be)`)
145146

146-
const proposedPieceInstances = getPieceInstancesForPart(
147-
context,
148-
playoutModel,
149-
previousPartInstance,
150-
playoutRundownModelForPart,
151-
part,
152-
await piecesThatMayBeActive,
153-
existingPartInstance.partInstance._id
154-
)
147+
// TMP: wrap in try/catch for troubleshooting:
148+
let proposedPieceInstances: PieceInstance[] = []
149+
try {
150+
proposedPieceInstances = getPieceInstancesForPart(
151+
context,
152+
playoutModel,
153+
previousPartInstance,
154+
playoutRundownModelForPart,
155+
part,
156+
await piecesThatMayBeActive,
157+
existingPartInstance.partInstance._id
158+
)
159+
} catch (e) {
160+
logger.error(
161+
`TROUBLESHOOTING: currentPartInstance: ${JSON.stringify(playoutModel.currentPartInstance)}`
162+
)
163+
logger.error(`TROUBLESHOOTING: nextPartInstance: ${JSON.stringify(playoutModel.nextPartInstance)}`)
164+
logger.error(
165+
`TROUBLESHOOTING: previousPartInstance: ${JSON.stringify(playoutModel.previousPartInstance)}`
166+
)
167+
168+
throw e
169+
}
155170

156171
logger.info(`Syncing ingest changes for part: ${partId} (orphaned: ${!!newPart})`)
157172

packages/job-worker/src/playout/adlibJobs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ export async function handleDisableNextPiece(context: JobContext, data: DisableN
438438

439439
return sortedPieces.find((piece) => {
440440
return (
441+
piece.pieceInstance.piece.enable.start !== 'now' &&
441442
piece.pieceInstance.piece.enable.start >= nowInPart &&
442443
((!data.undo && !piece.pieceInstance.disabled) || (data.undo && piece.pieceInstance.disabled))
443444
)

packages/job-worker/src/playout/infinites.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ export function getPieceInstancesForPart(
332332

333333
playingSegment = playingRundown.getSegment(playingPartInstance.partInstance.segmentId)
334334
if (!playingSegment) {
335+
// Double check that there are no parts using the old segment ids:
336+
// TODO: This whole section can probably be removed later, it's really unneccessary in the grand scheme of
337+
// things, it's here only to debug some problems
335338
const rundownId = playingRundown.rundown._id
336339
context.directCollections.Segments.findFetch({
337340
rundownId: rundownId,
@@ -344,11 +347,12 @@ export function getPieceInstancesForPart(
344347
)
345348
})
346349
.catch((e) => logger.error(e))
350+
// End of temporary section
347351

348352
throw new Error(
349353
`Segment "${playingPartInstance.partInstance.segmentId}" in Rundown "${
350354
playingRundown.rundown._id
351-
}" not found! (other segments: ${JSON.stringify(playingRundown.segments.map((s) => s.segment._id))})`
355+
}" not found! (partInstanceId: "${playingPartInstance.partInstance._id}", other segments: ${JSON.stringify(playingRundown.segments.map((s) => s.segment._id))})`
352356
)
353357
}
354358
}

packages/job-worker/src/playout/model/implementation/PlayoutModelImpl.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,12 @@ export class PlayoutModelImpl extends PlayoutModelReadonlyImpl implements Playou
567567
this.#baselineHelper.saveAllToDatabase(),
568568
])
569569

570+
// Clean up deleted partInstances, since they have now been deleted by writePartInstancesAndPieceInstances
571+
for (const [partInstanceId, partInstance] of this.allPartInstances) {
572+
if (partInstance !== null) continue
573+
this.allPartInstances.delete(partInstanceId)
574+
}
575+
570576
this.#playlistHasChanged = false
571577

572578
// Execute deferAfterSave()'s

packages/job-worker/src/playout/setNext.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,9 +279,11 @@ async function cleanupOrphanedItems(context: JobContext, playoutModel: PlayoutMo
279279

280280
const selectedPartInstancesSegmentIds = new Set<SegmentId>()
281281

282+
const previousPartInstance = playoutModel.previousPartInstance?.partInstance
282283
const currentPartInstance = playoutModel.currentPartInstance?.partInstance
283284
const nextPartInstance = playoutModel.nextPartInstance?.partInstance
284285

286+
if (previousPartInstance) selectedPartInstancesSegmentIds.add(previousPartInstance.segmentId)
285287
if (currentPartInstance) selectedPartInstancesSegmentIds.add(currentPartInstance.segmentId)
286288
if (nextPartInstance) selectedPartInstancesSegmentIds.add(nextPartInstance.segmentId)
287289

@@ -291,7 +293,7 @@ async function cleanupOrphanedItems(context: JobContext, playoutModel: PlayoutMo
291293

292294
const alterSegmentsFromRundowns = new Map<RundownId, { deleted: SegmentId[]; hidden: SegmentId[] }>()
293295
for (const segment of segments) {
294-
// If the segment is orphaned and not the segment for the next or current partinstance
296+
// If the segment is orphaned and not the segment for the previous, current or next partInstance
295297
if (!selectedPartInstancesSegmentIds.has(segment.segment._id)) {
296298
let rundownSegments = alterSegmentsFromRundowns.get(segment.segment.rundownId)
297299
if (!rundownSegments) {

0 commit comments

Comments
 (0)