rocky run --watch exits promptly when a signal lands between iterations. No test covers a signal landing during one, and the code path there ends in an unbounded wait.
Split out of #1405, whose signal-swallowing half is fixed (#1497) and whose suite-truncation half is fixed by #1589. This is the part neither closed.
What is covered today
engine/rocky/tests/run_watch.rs:291-324 waits for the run to complete before signalling. So the pinned behaviour is:
iteration ends -> signal -> select! fires -> exit TESTED
signal mid-run -> select! drops the iteration -> ??? NOT TESTED
Why the untested path may not be prompt
run_watch.rs:230-278 and :350-400 race each iteration against the signal streams, so the outer select! does drop the in-flight iteration future. But dropping the future is not the end of the work:
run_watch returns Ok(()).
engine/rocky/src/main.rs:3044 drops the tokio runtime.
- Runtime drop waits for every in-flight
spawn_blocking task. There is no shutdown_timeout.
The blocking tasks are DuckDB loader and adapter statements. Against the one-row test fixture that wait is milliseconds, which is why nothing has surfaced. Against a real warehouse a statement can run for minutes, and the process would sit there after the operator pressed Ctrl-C — the same user-visible symptom #1405 reported, reached by a different route.
Suggested work
Confidence
I have not reproduced this. It is derived from reading the path, and the reasoning could be wrong in one specific way: if every warehouse statement on the watch path is already cancellable or short, the runtime-drop wait is never long and there is nothing to fix. Running the test above is what settles it.
Related: #1405, #1497, #1589.
rocky run --watchexits promptly when a signal lands between iterations. No test covers a signal landing during one, and the code path there ends in an unbounded wait.Split out of #1405, whose signal-swallowing half is fixed (#1497) and whose suite-truncation half is fixed by #1589. This is the part neither closed.
What is covered today
engine/rocky/tests/run_watch.rs:291-324waits for the run to complete before signalling. So the pinned behaviour is:Why the untested path may not be prompt
run_watch.rs:230-278and:350-400race each iteration against the signal streams, so the outerselect!does drop the in-flight iteration future. But dropping the future is not the end of the work:run_watchreturnsOk(()).engine/rocky/src/main.rs:3044drops the tokio runtime.spawn_blockingtask. There is noshutdown_timeout.The blocking tasks are DuckDB loader and adapter statements. Against the one-row test fixture that wait is milliseconds, which is why nothing has surfaced. Against a real warehouse a statement can run for minutes, and the process would sit there after the operator pressed Ctrl-C — the same user-visible symptom #1405 reported, reached by a different route.
Suggested work
Runtime::shutdown_timeoutbelongs on the drop path, and what the budget is. That is a real trade-off: a timeout abandons a running warehouse statement, which is safe for a read and less obviously safe for anything else. Worth stating explicitly rather than picking a number.Confidence
I have not reproduced this. It is derived from reading the path, and the reasoning could be wrong in one specific way: if every warehouse statement on the watch path is already cancellable or short, the runtime-drop wait is never long and there is nothing to fix. Running the test above is what settles it.
Related: #1405, #1497, #1589.