Repository navigation
fix(parsers): find ffmpeg installed after a long-running preview started - #5439
Conversation
Edit accuracy: accurate 2061 (base branch 2061), smooth 1549 of thoseThe gate passes. Quarantined, measured but not gated (0) |
… probes stay cheap
somanshreddy
left a comment
There was a problem hiding this comment.
Approving at ffa53eb5.
- Found binaries are still cached for the process lifetime. Misses are now remembered for 5 s (
lastMissAt) instead of forever, so a burst of per-file probes on a machine without FFmpeg costs one search per 5 s. The env override is still re-read on every call, andclearFfBinaryLookupCacheclears both maps. ffBinaries.test.ts: 8/8. All 4 mutants are killed:- caching a miss forever
- no miss cache at all
- no found-binary cache
- TTL set to 0
- CI: all 11 required checks are green. No CRs.
- Heads-up: #5434 also edits
findFfBinary/searchSysteminffBinaries.ts(the npm installer fallback). Whichever lands second needs a rebase. The two compose cleanly as written: the installer lookup becomes part of the search, and its result is cached the same way.
Review by Somu
jrusso1020
left a comment
There was a problem hiding this comment.
Reviewed at ffa53eb5, focusing on cost on hot paths and how this interacts with #5434.
- No timers. The miss window is a
Date.now()comparison againstlastMissAt. Nothing is scheduled, so there's nothing to leak or keep the process alive.clearFfBinaryLookupCacheclears both maps. - Spawn cost. A hit is cached for the life of the process, as before, so a machine with FFmpeg never searches again. On a machine without it, each binary now re-runs
searchSystemat most once every 5 s. On Unix that's one synchronouswhich(execFileSync, 5 s timeout) plus a fewexistsSynccalls. It runs on the event loop, butwhichreturns at once on a miss, and a burst of per-file probes (preview rebuilds,mediaMetadata,peakMap,waveform) still costs one search per window. Fine for a lookup that used to happen once per process. - The test uses fake timers. It shows no second search inside the window, a find after the window, and the hit staying cached (two
whichcalls in total). - With #5434. Both rewrite
lookupOnSystemand the doc comment inffBinaries.ts, so whichever lands second needs a rebase. Behaviour composes cleanly: #5434's installer-package lookup sits inside the search, which only runs on a miss, and usescreateRequireresolution with no spawn. A rebased #5434 will also re-check its installer package every 5 s while nothing is found, which is what you want after annpm i @ffmpeg-installer/ffmpeg.
Nit, non-blocking: if the wall clock is set back, Date.now() - lastMiss goes negative and the miss is trusted until the clock catches up. performance.now() would avoid that.
Required checks are green at this head.
— Rames
…r-install # Conflicts: # packages/parsers/src/ffBinaries.test.ts # packages/parsers/src/ffBinaries.ts
jrusso1020
left a comment
There was a problem hiding this comment.
Re-approving at b6e6e4ae. That commit merges main (#5434) into ffa53eb5, the head I approved earlier.
I checked the merge resolution against a plain git merge-tree of the two parents. Both conflicts are resolved correctly:
ffBinaries.ts: the PR's split is kept.searchSystemruns the search, andlookupOnSystemcaches a hit for good and a miss forMISS_TTL_MS. Main's lookup order is kept too: PATH, then.hyperframes/bin, then common dirs, with the@ffmpeg-installerpackage last (findInCommonDirsOrInstallerPackage). The installer path therefore gets the same short miss cache.clearFfBinaryLookupCachestill clears both maps, and no conflict markers remain.ffBinaries.test.ts: main's installer tests and its "caches the miss until cleared" test are kept alongside the PR's late-install test. The miss test makes two back-to-back calls inside the TTL, so it holds under the new miss cache.
All 11 required checks pass at this head.
— Rames
What changes for a user
A Studio preview that was already running (for example one started with
hyperframes preview --background) now finds FFmpeg when it is installed after the preview started. Before, Export kept answering "FFmpeg not found" until the preview was restarted.Why
The shared FFmpeg/ffprobe lookup (
findFfBinaryin@hyperframes/parsers) cached a miss for the life of the process. It already searches PATH and the common install folders (/opt/homebrew/bin,/usr/local/bin,/usr/bin, ...), but after the first miss it never looked again. It now caches a found binary for the life of the process and remembers a miss for only 5 seconds, so a lookup a few seconds after an install finds it. Every FFmpeg caller (render, preflight, transcode, proxy) goes through this one lookup.The 5-second window keeps per-file callers cheap on a machine without FFmpeg (Studio's preview probes each video on every rebuild): a burst of lookups costs one search, not one per file.
Checked
ffBinaries.test.ts: a miss, then the binary appears in a common install folder with PATH empty; it stays a miss within 5 seconds (no second search), then is found and cached. It fails on main (expected undefined to be '/opt/homebrew/bin/ffmpeg') and passes three runs in a row. Parsers suite: 1265 pass; the CLI and studio-server tests that use the lookup pass./usr/binfor that process only, the same request started a render (200) with this change, and still answered 503 on main.Not covered: on Windows the lookup searches the current directory and the process's PATH only, so an install that only adds itself to the user's PATH (winget) is not seen by a server that is already running.