You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
External convert timeout can hang forever (weasyprint on large CSV) #3359
Large CSV/text files converted with weasyprint can pin a process-item job for hours. Progress sits around 20%. Last job log lines look like:
Running external command: weasyprint …
Waiting for command to terminate…
docspell.joex.convert.weasyprint.command.timeout is set (default is 2 minutes). It does not kill these jobs. Other conversions on the same host do log real timeouts (Timed out after: 120000 ms), so the setting is live. These hung weasyprint runs just never get there.
If you kill the weasyprint OS process yourself, Docspell wakes up, skips the PDF, and finishes the item. Addons run. So the failure path is fine. The timeout path never reaches it.
Setup where we saw it
joex around v0.46
text/csv through weasyprint, files in the 3–10 MB range
weasyprint stuck at ~100% CPU on those files for a long time
Why I think it hangs
SysExec.waitFor does call Process.waitFor(timeout). When that returns "still running", it joins the stdout/stderr log fibers before raising TimeoutException:
Those fibers come from logOutputs / consumeOutputs. They only finish when the child closes its pipes. On timeout the child is still alive, so the join never returns. TimeoutException never fires. Resource cleanup never calls destroy(). You get a permanent hang after "Waiting for command to terminate…".
ExternConv.toPDF uses that path for weasyprint.
Note: WeasyPrint's own -t / --timeout only limits HTTP fetches for remote assets. It does not bound conversion time, so wiring that into args would not fix this.
What I'd expect
When command.timeout elapses, destroy the process (forcibly if needed), fail the conversion with a timeout, and let process-item continue without a PDF.
Fix direction
On timeout, destroy the process first, then cancel/join the log fibers, then raise TimeoutException. Soft destroy() may not be enough if weasyprint ignores it under load.
Workaround
Kill stuck weasyprint processes in the joex container. Jobs then continue.
Related in spirit to #3345 (external converter blocking workers), but this one is specifically timeout vs log-drain ordering in SysExec.
Result: conversion fails with timeout and process-item continues (text extraction / analysis) instead of hanging on Waiting for command to terminate….
Converting file Some(hang.csv) … into a PDF
PDF conversion failed: Timed out after: 3000 ms. Go without PDF file
Starting text extraction for 1 files
Extracting text for attachment hang.csv finished in 66 ms
Starting text analysis
Activity
test(common): cover SysExec timeout with open pipes and noisy stderr
tiborrr commentedon Oct 2, 2026
Local joex + restserver verification
Ran this branch locally with restserver + joex (0.44.0-SNAPSHOT) after replacing
docspell-commonwith the fixed jar.Setup:
hang.csvweasyprintreplaced with a fake binary that reads stdin then hangs forever (open pipes)docspell.joex.convert.weasyprint.command.timeout = 3 secondsResult: conversion fails with timeout and
process-itemcontinues (text extraction / analysis) instead of hanging onWaiting for command to terminate….Screenshot from the local run:
Full snippet: https://github.com/tiborrr/docspell/blob/fix/sysexec-timeout-destroy/docs/pr-evidence/pr3360-joex-timeout-snippet.txt