fix: the remaining Unbounded workflow histories sub-items - #449
Conversation
3aa26bc to
f5aa249
Compare
f5aa249 to
a353c1d
Compare
|
Trimmed in What stays is the part that is not recoverable by reading the code: why the version gate exists, why the channel has to be empty before continuing as new, why the clip fields are narrowed and where to add one, and why the cleanup result carries counts instead of paths. One went entirely rather than shrinking: the note explaining that the per-folder log line had moved below the error check described the change rather than the code, and the line reads fine on its own. |
a353c1d to
0f57e7b
Compare
|
Confirmed and fixed. It is gone. This branch no longer touches While in there I also removed the add-and-revert pair from #448 itself, so its history is now just the selector change and the copy/catch-up fix rather than three commits arguing with each other. The whole stack was rebased with the correct upstream this time and force-pushed; |
0f57e7b to
043709d
Compare
|
Related to the P1 on #448: the
No test for it: the test environment cannot make To be clear about the other half of that review comment: this branch does not need a |
3296bf2 to
031c76a
Compare
The finding calls this an eternal fixed-ID signal workflow whose history is never reset. It is not eternal: ReceiveWithTimeout gives up after ten seconds and the run completes, to be started again by the next SignalWithStartWorkflow. The exposure is narrower and real. Requests arriving less than ten seconds apart keep one run alive indefinitely, and every move adds a GetShapes call plus one MoveFileWait per shape to the same history — so a bulk move never lets the run end and never resets the history. It now continues as new when the server suggests it, which is the signal that takes the actual event count and size into account rather than a threshold guessed here. The check runs only while the signal channel is empty, so no queued request is dropped; a request that arrives after the check but before the server applies the continue-as-new is handled by the server, which turns an unhandled signal at completion into a new workflow task. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
a4e799c to
5394cc6
Compare
MergeExportData computed its merge inputs inside a workflow.SideEffect, which writes the returned value into the history as a marker. For a long export that value is every clip path, every language and every offset — recorded once as the marker and again in the activity inputs derived from it. exportDataToMergeInputs takes an ExportData and two paths and returns a value; nothing in it reads a clock, a file or a global, so the SideEffect bought nothing. It does range over the per-clip audio and subtitle maps, which is why it now sorts those keys: each language accumulates into its own MergeInput so the order was already immaterial, but running in workflow code it has to be visibly so — to workflowcheck and to the next reader. Unguarded: this changes what the workflow writes to its history, so an export started before the deploy fails to replay it. None has to survive the deploy. Four tests, including one that calls the function fifty times and compares, so a future edit that lets map order leak into the result is caught rather than being caught by a customer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CleanupTemp sweeps around sixty folders and returned the full list of deleted paths as its result. A workflow result is written into the completion event, so a fortnight of temp files landed in the history and in every caller that fetches the result — to say something a number says. DeletedFiles is replaced by DeletedCountPerRoot, which is more useful for the thing the result is actually read for: seeing that a folder is not being cleaned. The paths are still in the activity results and the worker logs. The per-folder log line moves below the error check, where it can report the folder it just finished rather than the running total — as written it logged 0 for the first folder no matter how much it had deleted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ption The transcription arrives as a workflow argument, and a workflow argument is stored in the WorkflowExecutionStarted event. A word-level transcription of a long programme runs to megabytes, so every import writes that into the history — and a big enough one does not merely bloat it, it exceeds Temporal's payload limit and the workflow cannot be started at all. SubtitlesFile is an alternative input: point it at the same JSON on shared storage and an activity reads it, keeping the payload out of the history. When it is set, Subtitles is ignored. Subtitles is kept rather than replaced. Nothing in this repository starts ImportSubtitles — it is registered and triggered from outside — so the field cannot be removed until whatever produces the transcription has moved over. The comment on it says why to prefer the path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Roughly a quarter of the lines added by this branch were comment, and most of the excess was the commit message written into the source a second time — why the change was made rather than what a reader of the code needs. What stays is the part that is not recoverable from the code: why the channel has to be empty before continuing as new, why the merge inputs are sorted, and why the cleanup result carries counts. What goes is the retelling around it. One comment went entirely rather than shrinking: the note explaining that the per-folder log line had moved below the error check described the change, not the code, and the line reads correctly on its own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5394cc6 to
c7516d2
Compare
10/n of a stack. Base:
fix/incremental-ingest-signal-selector(#448). One commit per sub-item — the last three of the Unbounded workflow histories finding, after the two loops in #447 and #448.MoveFilesWorkerFlowcontinues as new —909ef4dThe finding calls it an eternal fixed-ID signal workflow whose history is never reset. It is not eternal:
ReceiveWithTimeoutgives up after ten seconds and the run completes, restarted by the nextSignalWithStartWorkflow.The real exposure is narrower. Requests arriving less than ten seconds apart keep one run alive indefinitely, and every move adds a
GetShapesplus oneMoveFileWaitper shape to the same history — a bulk move never lets the run end. It now continues as new when the server suggests it, and only while the signal channel is empty so no queued request is dropped. A request landing after the check is handled by the server, which turns an unhandled signal at completion into a new workflow task.MergeExportDatastops persisting a marker —049131aexportDataToMergeInputsran inside aworkflow.SideEffect, which writes its return value into the history as a marker: every clip path, language and offset, recorded once as the marker and again in the activity inputs derived from it. The function reads no clock, file or global, so theSideEffectbought nothing.It does range over the per-clip audio and subtitle maps, so those keys are now sorted — each language accumulates into its own
MergeInputso the order was already immaterial, but running in workflow code it has to be visibly so, toworkflowcheckand to the next reader.No
workflow.GetVersionguard: this changes what the workflow writes to its history, so an export started before the deploy fails to replay it. None has to survive the deploy.CleanupTempreturns counts —36d239cIt sweeps ~60 folders and returned every deleted path as its result, which goes into the completion event.
DeletedFilesis replaced byDeletedCountPerRoot, which is what the result is actually read for — seeing a folder that is not being cleaned. Paths remain in the activity results and worker logs.Also moved the per-folder log line below the error check, where it can report the folder it just finished: as written it logged the running total, so it printed
0for the first folder however much it had deleted.ImportSubtitlescan take a path —ea0e06dA word-level transcription of a long programme is megabytes, and a workflow argument lives in the
WorkflowExecutionStartedevent. A big enough one does not merely bloat the history, it exceeds Temporal's payload limit and the workflow cannot start.SubtitlesFileis an alternative input read by an activity.Subtitlesis kept, not replaced — nothing in this repository startsImportSubtitles, so the field cannot go until whatever produces the transcription has moved over.Dropped:
VXExportsending children narrowed clipsThe fifth sub-item, trimming the per-destination
ExportDatacopies down to the clip fields the children read, is no longer in this PR. The parent history already carries the fullExportDatatwice — theGetExportDataActivityresult and theMergeExportDatachild input, which has to be complete — so narrowing the destination copies saved a fraction of what was already there, on a payload never close to Temporal's limit. It bought that by making any field a child later reads silently zero. Not worth the trade.🤖 Generated with Claude Code