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
fix: [sc-106109] Wait for actual process exit before replacing or deleting agent files (#100)
Install, update and uninstall waited for the old agent process to exit by sleeping
a fixed 5 seconds and then acting regardless: runUpdate overwrote the agent
executable in place, runUninstall deleted the installation directory. On a loaded
endpoint the old process is frequently still alive at the 5 second mark - its
shutdown legitimately drains in-flight commands, tears down MQTT and kills its
plugin subprocesses one at a time - and Windows refuses to replace a running
image, so the update failed with a sharing violation after the service was
already stopped, leaving the device offline with nothing to retry. Uninstall had
the mirror-image problem: files removed out from under a live process, leaving an
installation that neither ran nor reinstalled.
The four sleeps are replaced with a wait on real exit signals, all of which must
clear: the service manager no longer reporting the service active, no process
still executing the agent binary, and the executable no longer held open (a
sharing violation on Windows, ETXTBSY on Linux). The three overlap on purpose -
the file signal is what actually blocks the write on Windows, but macOS permits
writing to a running image, and a service manager can report a service stopped
while its process is still winding down. The wait returns on the first round of
probes when the process is already gone, so a healthy update is faster than the
unconditional sleep it replaces, and is bounded by a documented 2 minute deadline
sized for a slow but legitimate shutdown. An elapsed poll interval is never by
itself treated as evidence of an exit; a probe that cannot run at all is logged
once at Warn and the remaining signals are used.
Overrunning the deadline aborts before anything is written or deleted, logging
what was still outstanding and for how long. Update then restarts the service it
stopped - on any failure after the stop, not just this one - so a failed update no
longer leaves an endpoint silently offline; install does the same; uninstall logs
plainly that nothing was removed. The agent executable and config file are now
written to a temp file in the destination directory and atomically renamed into
place, mirroring the postback spool, so a failed or interrupted write leaves the
previous file byte-identical instead of truncated. The re-registration path's
sleep is replaced by polling until the deleted registration is actually reaped.
exitTimeoutOverrideStr is overridable via -ldflags (25s in the integration build)
so the deadline case can be observed in seconds, mirroring stopTimeoutOverrideStr.
0 commit comments