fix: serialize daemon restart and termination - #774
Conversation
29b3632 to
68d90b3
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #774 +/- ##
==========================================
+ Coverage 25.42% 26.28% +0.86%
==========================================
Files 133 134 +1
Lines 12639 12917 +278
==========================================
+ Hits 3213 3395 +182
- Misses 9036 9110 +74
- Partials 390 412 +22
🚀 New features to boost your workflow:
|
Zephyrcf
left a comment
There was a problem hiding this comment.
Thanks for this pr. Here are a few questions:
@Zephyrcf Thanks for the review. I’ve addressed all the comments and updated the code accordingly. Please take another look when convenient. |
|
@qinfustu plz squash the commits. |
51a5374 to
05577da
Compare
@Zephyrcf Thanks! Security scan is still failing with GO-2026-5970. How should we handle it? |
fix: serialize daemon restart and termination
2540dbd to
5579b1c
Compare
|
This collides with #773: both add On Also still open: @Zephyrcf asked for a squash. |
Overview
When a nydusd daemon death event is received, the manager now terminates the
old daemon process before starting a new one, and serializes recovery so that
only one recovery routine runs per daemon at a time. This prevents zombie/
orphan nydusd accumulation and avoids duplicate concurrent restarts.
Related Issues
Related #771
Change Details
Previously, on a daemon death event
doDaemonRestart/doDaemonFailoveronlycalled
d.Wait()and then started a new nydusd. When the death event was afalse positive (the API socket closed while the process was hung), the old
process kept running while a new one was spawned, and duplicate death events
could trigger multiple concurrent recoveries. Over time this leaked orphan
nydusd processes that kept hitting the registry.
This PR makes recovery robust:
terminateDaemonProcess):os.Processhandle first (uses a pidfd on Linux) to pin thehandle to the specific process before any identity check, eliminating a
PID-reuse TOCTOU.
/proc/<pid>/cmdline(matching--apisock)and classifies it as alive / zombie / gone / reused.
SIGTERM, waits with a timeout, then escalatesto
SIGKILL; for a zombie: reaps it viaWait()with a timeout; forgone/reused: does nothing.
unmonitored live process behind. Unsubscribe now happens only after
successful termination.
recoveryInFlight sync.MaponManager):beginDaemonRecoveryusesLoadOrStoreto dedup concurrent death events;the flag is cleared when the recovery goroutine finishes.
subscribed process PID in
deathEvent, andhandleDaemonDeathEventignoresevents whose PID no longer matches the daemon's current PID (generation
check), preventing a delayed event for an old process from killing its
replacement.
// TODO: ratelimitand readsd.Pid()under the daemon lock(
daemonProcessID) to avoid a data race.Test Results
Added unit tests in
pkg/manager/daemon_event_test.goand updatedmonitor_test.go:TestBeginDaemonRecoverySerializesConcurrentCalls– dedup guard.TestInspectDaemonProcess– alive / zombie / gone / reused classification.TestTerminateDaemonProcessEscalatesToKill– SIGTERM → SIGKILL escalation.TestTerminateDaemonProcessReapsZombie– zombie reap path.TestTerminateDaemonProcessReturnsSignalErrorWithoutWaiting– abort onsignal failure.
TestHandleDaemonDeathEvent_*– removed-daemon skip, dedup skip, flag clear,stale-PID skip.
TestLivenessMonitor– verifies the PID is propagated in the death event.Change Type
Please select the type of change your pull request relates to:
Self-Checklist
Before submitting a pull request, please ensure you have completed the following: