nix-eval-jobs: handle worker interruption properly

Right now, the worker will not receive interrupts, as it has no signal handler
thread due to the way it forks, but this will change soon. Prepare to handle
worker interruption properly, by letting the worker exit successfully in this
case and adjusting the coordinator to handle this exit gracefully.

Change-Id: I9f79670b0d2004e7e2d8bf36cf67108e6a6a6964
This commit is contained in:
Alois Wohlschlager
2025-11-25 11:50:59 +00:00
committed by alois31
parent 9d01255046
commit 441f7db5f1
3 changed files with 18 additions and 1 deletions
+2
View File
@@ -56,6 +56,8 @@ Drv::Drv(std::string &attrPath, nix::EvalState &state, nix::DrvInfo &drvInfo,
assert(optOutputPath);
outputs[outputName] = state.ctx.store->printStorePath(*optOutputPath);
}
} catch (const nix::Interrupted &) {
throw;
} catch (const std::exception &e) { // NOLINT(lix-foreign-exceptions)
state.ctx.errors.make<nix::EvalError>(
"derivation '%s' does not have valid outputs: %s",
+12 -1
View File
@@ -161,7 +161,18 @@ void handleBrokenWorkerPipe(Proc &proc, std::string_view msg, bool retry = true)
strerror(errno));
} else {
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == 1) {
if (WEXITSTATUS(status) == 0) {
// On the user hitting Ctrl-C, both the worker and the coordinator will receive the signal.
// When the worker is interrupted, it will "unexpectedly" exit successfully.
// Check whether the coordinator was interrupted as well, and don't show an ugly error in this case.
checkInterrupt();
// Maybe the coordinator noticed the broken pipe before its own interrupt.
// Wait for a bit and try again.
std::this_thread::sleep_for(std::chrono::seconds(1));
checkInterrupt();
// No, the coordinator was not interrupted, possibly the signal was sent manually to the worker.
// Show the error in this case.
} else if (WEXITSTATUS(status) == 1) {
throw Error(
"while %s, evaluation worker exited with exit code 1, "
"(possible infinite recursion)",
+4
View File
@@ -252,6 +252,8 @@ try {
// Don't forget to print it into the STDERR log, this is
// what's shown in the Hydra UI.
std::cerr << msg << "\n";
} catch (const nix::Interrupted &) {
throw;
} catch ( // NOLINT(lix-foreign-exceptions)
const std::exception &e) { // FIXME: for some reason the catch block
// above, doesn't trigger on macOS (?)
@@ -282,6 +284,8 @@ try {
if (tryWriteLine(to.get(), "restart") < 0) {
return; // main process died
};
} catch (const nix::Interrupted &) {
// The coordinator should get the interrupt too, so it doesn't need to be logged.
} catch (nix::Error &e) {
nix::JSON err;
auto msg = e.msg();