diff --git a/RenderPipeline2.md b/RenderPipeline2.md index 481544b..4cd12c9 100644 --- a/RenderPipeline2.md +++ b/RenderPipeline2.md @@ -1292,6 +1292,11 @@ The panel keeps all existing capabilities (episode/shot discovery, overlays, pic | Latest Export + QC status | new E2 `exports/latest` — e.g. `v004 — READY_FOR_QC`, `v004 — RENDERING 42% (ETA 1:36 on RENDER-01)`, `v003 — QC FAILED: "grain mismatch"` | While an export is active the panel polls E2 every 15 s to live-update the header. +The poll stops when the export leaves an active status, and also when the panel is +closed or reloaded — `app.scheduleTask` outlives the panel instance that armed it, +so the task id is kept in ExtendScript global scope where the next instance can +still cancel it. The export is unaffected either way: it runs on the farm, and the +header picks its status back up on the next Refresh. ### 12.2 Buttons and their API calls diff --git a/VFXReviewConnector.jsx b/VFXReviewConnector.jsx index a740d4e..aa618df 100644 --- a/VFXReviewConnector.jsx +++ b/VFXReviewConnector.jsx @@ -32,7 +32,7 @@ var SETTINGS_KEY = "cfg"; // Bump on every change deployed to a workstation. The panel reports this to // the server on load, so Pipeline → Machines shows which version each machine // is actually running and flags the ones left behind. -var PANEL_VERSION = "2.6.0"; +var PANEL_VERSION = "2.6.1"; (function VFXReviewConnector(thisObj) { var uiState = { @@ -65,7 +65,6 @@ var PANEL_VERSION = "2.6.0"; var pipelineState = { pollShotCode: null, - pollTaskId: 0, prefilledShotCode: null }; @@ -3862,13 +3861,34 @@ var PANEL_VERSION = "2.6.0"; } } + // A scheduled task outlives the panel instance that armed it. Held only in + // this closure, the id of a repeating task goes with the instance when the + // panel is closed or reloaded, and nothing can cancel it again: it fires + // every 15 s for the rest of the AE session, and every tick that lands + // while a modal dialog is open raises "Cannot run a script while a modal + // dialog is waiting for response." The id therefore lives beside the tick + // in global scope, where the next instance can still reach it. + var POLL_TASK_ID_KEY = "__vfxrExportPollTaskId"; + + function getPollTaskId() { + var taskId = $.global[POLL_TASK_ID_KEY]; + + return (typeof taskId === "number" && taskId > 0) ? taskId : 0; + } + + function setPollTaskId(taskId) { + $.global[POLL_TASK_ID_KEY] = taskId || 0; + } + function stopExportPolling() { - if (pipelineState.pollTaskId) { + var taskId = getPollTaskId(); + + if (taskId) { try { - app.cancelTask(pipelineState.pollTaskId); + app.cancelTask(taskId); } catch (cancelError) { } - pipelineState.pollTaskId = 0; + setPollTaskId(0); } pipelineState.pollShotCode = null; } @@ -3902,9 +3922,9 @@ var PANEL_VERSION = "2.6.0"; stopExportPolling(); pipelineState.pollShotCode = shotCode; try { - pipelineState.pollTaskId = app.scheduleTask("__vfxrExportPollTick()", 15000, true); + setPollTaskId(app.scheduleTask("__vfxrExportPollTick()", 15000, true)); } catch (scheduleError) { - pipelineState.pollTaskId = 0; + setPollTaskId(0); } } @@ -5023,6 +5043,11 @@ var PANEL_VERSION = "2.6.0"; return win; } + // A previous instance may have left a repeating poll armed, and its shot + // code went with that closure. Cancel it before the tick is pointed at this + // instance, rather than letting it fire into a fresh, empty state. + stopExportPolling(); + // app.scheduleTask evaluates in global scope — expose the poll tick there $.global.__vfxrExportPollTick = pollExportTick; @@ -5033,6 +5058,13 @@ var PANEL_VERSION = "2.6.0"; diagLog("panel v" + PANEL_VERSION + " loaded on " + getHostName()); reportPanelVersion(); + // Closing the panel leaves an armed task running with no UI left to update. + // The export itself is unaffected: it runs on the farm, and the panel picks + // its status back up from the server on the next Refresh. + panel.onClose = function () { + stopExportPolling(); + }; + if (panel instanceof Window) { panel.center(); panel.show();