What
clearJobs() can enter an infinite loop that pins one CPU core permanently and silently disables auto-delete forever.
Observed on a container that ran 89 days at a constant 22.5% CPU (483 CPU-hours) with no conversions active and no ffmpeg running — only the bun main thread spinning, all worker threads idle.
Why
Two things combine:
1. src/pages/download.tsx:28 returns Bun.file(filePath). A read fd on the served file can outlive the response. Confirmed via /proc/<pid>/fd:
lr-x------ 1 root root 14 -> /app/data/output/<user>/<job>/<name>.h264.mp4 (deleted)
2. src/index.tsx:80 then runs rmSync(dir, { recursive: true, force: true }) on that directory.
On a FUSE filesystem (here Unraid's shfs at /mnt/user; same applies to sshfs/mergerfs), unlinking a file that still has an open fd does not remove the directory entry — FUSE renames it to .fuse_hidden<hex>. So rmSync never converges:
unlink → FUSE re-creates it as .fuse_hidden… → rmdir fails ENOTEMPTY → readdir → unlink → …
The name is different on every pass:
$ ls -A output/<user>/<job>
.fuse_hidden0073584d3d30e9dd
.fuse_hidden0073584d3d30e9e0
.fuse_hidden0073584d3d30e9e2
Syscall sampling over the lifetime of the process shows only unlinkat (263) and openat (257).
Impact
clearJobs() reschedules itself on its own last line (src/index.tsx:93). Because it never returns, that timer is never armed — auto-delete is permanently dead for the life of the process, not just for the offending job.
In my case files from April were still present in July, including a stranded 111 MB upload. Only a container restart cleared it.
Reproduce
- Put
/app/data on a FUSE mount.
- Convert a file and download it. (I could not pin down the exact condition that leaks the fd — I only observed the leaked read fd afterwards.)
- Wait
AUTO_DELETE_EVERY_N_HOURS.
Suggested fix
- Pass
maxRetries to rmSync so the retry loop is bounded.
- Wrap the per-job deletion in
try/catch so one undeletable job can't block the others.
- Move the
setTimeout reschedule into a finally so a throw or hang can't permanently kill cleanup.
- Explicitly close the
Bun.file handle when the download response ends.
Versions
Observed on image sha256:e1f85be04bbaf8a55ead9261194c3ae0fa0957d303ea537127154860b2552afd. The relevant code is unchanged in current main — verified src/index.tsx:72-94 and src/pages/download.tsx:28 at v0.18.0.
Host: Unraid 7.2.4, /app/data bound to /mnt/user/appdata-array/convertx (shfs/FUSE).
What
clearJobs()can enter an infinite loop that pins one CPU core permanently and silently disables auto-delete forever.Observed on a container that ran 89 days at a constant 22.5% CPU (483 CPU-hours) with no conversions active and no ffmpeg running — only the
bunmain thread spinning, all worker threads idle.Why
Two things combine:
1.
src/pages/download.tsx:28returnsBun.file(filePath). A read fd on the served file can outlive the response. Confirmed via/proc/<pid>/fd:2.
src/index.tsx:80then runsrmSync(dir, { recursive: true, force: true })on that directory.On a FUSE filesystem (here Unraid's shfs at
/mnt/user; same applies to sshfs/mergerfs), unlinking a file that still has an open fd does not remove the directory entry — FUSE renames it to.fuse_hidden<hex>. SormSyncnever converges:unlink → FUSE re-creates it as
.fuse_hidden…→rmdirfailsENOTEMPTY→ readdir → unlink → …The name is different on every pass:
Syscall sampling over the lifetime of the process shows only
unlinkat(263) andopenat(257).Impact
clearJobs()reschedules itself on its own last line (src/index.tsx:93). Because it never returns, that timer is never armed — auto-delete is permanently dead for the life of the process, not just for the offending job.In my case files from April were still present in July, including a stranded 111 MB upload. Only a container restart cleared it.
Reproduce
/app/dataon a FUSE mount.AUTO_DELETE_EVERY_N_HOURS.Suggested fix
maxRetriestormSyncso the retry loop is bounded.try/catchso one undeletable job can't block the others.setTimeoutreschedule into afinallyso a throw or hang can't permanently kill cleanup.Bun.filehandle when the download response ends.Versions
Observed on image
sha256:e1f85be04bbaf8a55ead9261194c3ae0fa0957d303ea537127154860b2552afd. The relevant code is unchanged in currentmain— verifiedsrc/index.tsx:72-94andsrc/pages/download.tsx:28at v0.18.0.Host: Unraid 7.2.4,
/app/databound to/mnt/user/appdata-array/convertx(shfs/FUSE).