diff --git a/changelog.d/1014-director-callback-failures.md b/changelog.d/1014-director-callback-failures.md index 65118b7a9..f3877eca4 100644 --- a/changelog.d/1014-director-callback-failures.md +++ b/changelog.d/1014-director-callback-failures.md @@ -1 +1,4 @@ -Director clock listeners, interaction observers and scene release failures no longer leave the director inconsistent, and a phase error is kept when cleanup also fails (deepeshbind, #1014). +- Director clock listeners, interaction observers and scene release failures + no longer leave the director inconsistent: each scene is released once, and + a phase error is kept (with the release failure logged) when cleanup also + fails (deepeshbind, #1014). diff --git a/src/director/playback.js b/src/director/playback.js index 2e243d748..3c060b2bb 100644 --- a/src/director/playback.js +++ b/src/director/playback.js @@ -54,7 +54,7 @@ export async function playSceneQueue( const cancelled = () => Boolean(token.cancelled || token.signal?.aborted); let activeScene = null; let completedShots = 0; - let runError = null; + let runFailed = false; try { if (!queue.length || cancelled()) { return { @@ -86,7 +86,7 @@ export async function playSceneQueue( if (!cancelled()) await adapter.complete?.(); return { status: cancelled() ? 'cancelled' : 'completed', completedShots }; } catch (error) { - runError = error; + runFailed = true; throw error; } finally { if (releaseOnFinish && activeScene) { @@ -95,7 +95,7 @@ export async function playSceneQueue( try { await adapter.releaseScene(toRelease); } catch (error) { - if (runError) { + if (runFailed) { console.warn('[Scenes] Scene release failed:', error); } else { throw error; diff --git a/src/director/playback.test.mjs b/src/director/playback.test.mjs index 0141f2b01..820e8186e 100644 --- a/src/director/playback.test.mjs +++ b/src/director/playback.test.mjs @@ -239,3 +239,25 @@ test('a failing inter-scene release releases the active scene only once', async ); assert.deepEqual(released, ['a']); }); + +test('a falsy phase failure is still preserved over a release failure', async () => { + const releaseError = new Error('release failed'); + const origWarn = console.warn; + console.warn = () => {}; + try { + const f = fixture({ + travel: async () => { + throw undefined; + }, + releaseScene: async () => { + throw releaseError; + }, + }); + await assert.rejects( + playSceneQueue(buildPlaybackQueue(scenes, 'a', { single: true }), f), + (error) => error === undefined, + ); + } finally { + console.warn = origWarn; + } +});