diff --git a/lix/libstore/build/derivation-goal.cc b/lix/libstore/build/derivation-goal.cc index 7eb51a027..fc8640442 100644 --- a/lix/libstore/build/derivation-goal.cc +++ b/lix/libstore/build/derivation-goal.cc @@ -1029,6 +1029,9 @@ try { co_return HookResult::Decline{}; } + // make sure we don't launch an unbounded number of build hooks + auto hookSlot = co_await worker.hook.instancesSem.acquire(); + if (!worker.hook.instances.empty()) { hook = std::move(worker.hook.instances.front()); worker.hook.instances.pop_front(); @@ -1062,6 +1065,9 @@ try { throw Error("bad hook reply '%s'", buildResp.which()); } + // the build was accepted by the hook, we can free the slot for another build now + hookSlot = {}; + machineName = rpc::to(buildResp.getAccept().getMachineName()); auto runReq = buildResp.getAccept().getMachine().runRequest(); diff --git a/lix/libstore/build/worker.hh b/lix/libstore/build/worker.hh index ebdd50965..096f99316 100644 --- a/lix/libstore/build/worker.hh +++ b/lix/libstore/build/worker.hh @@ -204,6 +204,10 @@ private: public: struct HookState { + // make sure we never have too many remote build hook processes waiting. they are + // expensive to start and may be requested in great numbers for wide build trees. + // the original implementation only allowed a single process, we allow some more. + AsyncSemaphore instancesSem{4}; std::list> instances; /**