(
May 28, 2026
)

Surviving Your Own Auto-Updater: A Windows-Only Problem We Didn't See Coming

A routine Windows auto-update could force-close and delete an app's install directory, taking Influxx's background daemon and every live session with it.
Surviving Your Own Auto-Updater: A Windows-Only Problem We Didn't See Coming
Surviving Your Own Auto-Updater: A Windows-Only Problem We Didn't See Coming
A routine Windows auto-update could force-close and delete an app's install directory, taking Influxx's background daemon and every live session with it.

An auto-updater exists to do one job: replace the old version of an application with the new one without breaking anything the user cares about. On Windows, the standard mechanism most installers use to do that job — force-close every process whose running image lives inside the install directory, delete that directory outright, then write the new version's files into its place — quietly assumes nothing important is still running from in there. Influxx's background daemon, the process that keeps every terminal session and every agent alive independent of the main window, lived exactly there by default. That meant a routine, silent Windows update could force-close the daemon and delete the very files it was executing from, killing every live terminal session and every agent running inside it, mid-update, with zero warning — a failure mode that barely exists on macOS or Linux, and one we didn't see coming until Windows showed it to us directly.

A Daemon That Was Never Supposed to Notice an Update

Every terminal session in Influxx — every agent CLI running, every long shell command still working after you've stopped watching it — is kept alive by a background daemon, not by the application window itself. Close the window and the daemon keeps sessions running underneath it; reopen Influxx and it reattaches to exactly where things were, which is the entire point for an agent working through a large refactor overnight, or a job you want to check on from your phone later.

The simplest way to build that daemon is to fork it from the application's own binary and let it live in the same directory the application was installed to. That's what Influxx did, and on macOS and Linux it causes no problem at all, because update mechanics on those platforms don't treat a running process's own files as disposable. It was a reasonable default. It just wasn't one all three of our target platforms actually agreed with.

What a Windows Installer Actually Does When It Updates You

Most Windows desktop apps ship their auto-updater through an NSIS-based installer, the standard, well-understood way to package a Windows update. Its mechanics are blunt and, for almost any application, perfectly safe: find every running process whose executable image lives inside the install directory, force-close it, delete the entire directory outright, and write the new version's files into the now-empty space. No negotiation, no waiting for a process to finish — the sequence assumes nothing running from inside an install folder is worth protecting from a routine update.

For most software that assumption holds, because most software has nothing meaningful running in the background between launches. Influxx broke it directly: our daemon's running image lived inside the install directory too, so the installer saw it as exactly the kind of disposable file the update was designed to force-close and delete. Picture what that means in practice — an agent working through a migration overnight, three CLIs running against different worktrees while you step away for the afternoon. Windows would apply a pending update on its own schedule, force-close the daemon, and delete the directory it was running from, and every terminal session and every agent inside it would die at that instant, mid-task, with no dialog box and no error to explain why. Nothing would crash. No exception would fire. Windows would be doing exactly what it was built to do; it was just built around an assumption Influxx's own architecture violated by default.

"Windows isn't wrong to force-close and wipe an install directory during an update — for the overwhelming majority of applications, there's nothing in there worth protecting. We just hadn't fully reckoned with the fact that our daemon's own running image made it look, from the installer's point of view, exactly like collateral. Nothing crashed. Nothing logged an error. The installer did its job perfectly, and that was the problem."

— Marcus Webb, Principal Systems Engineer at ETAPX

Getting the Daemon Out of the Blast Radius

The fix was simple to state and required real care to execute: stop letting the daemon live anywhere the installer considers its own territory. On Windows specifically, Influxx now copies the daemon's entire runtime out of the install directory before it ever runs, into a separate, versioned location outside the installer's reach — a per-version folder under the user's local application-data directory, rather than the install folder the updater is allowed to erase.

The Whole Runtime, Not Just the Executable

Relocating "the daemon" means moving an entire closure of files together, not just one executable: the renamed daemon executable itself; the JavaScript engine's startup data — the ICU and snapshot files most Node-based runtimes quietly depend on; and the full native module tree the daemon links against, including the native terminal library that drives a real console session on Windows. Miss any piece and the relocated daemon either fails to start or fails the moment it opens a real terminal, so the whole closure moves together, versioned as one unit.

A Different Name, On Purpose

The relocated daemon also runs under a process image name distinct from the main application's — not cosmetic. The installer's kill logic is path-based, targeting anything inside the install directory regardless of name. But other Windows tooling — antivirus software, process managers, an ad hoc script someone wrote — sometimes matches by name instead, and a daemon sharing the app's name is an easy thing to target by mistake. A distinct name removes it from both kinds of blast radius at once: path-based logic no longer finds it in the install directory, and name-based logic no longer recognizes it as the app it's watching for.

"I had a Windows update sitting in the notification tray for two days because I didn't want to risk it mid-task. I finally let it run while I had two agents going against a big migration overnight, expecting to come back to a dead window. Everything was still there in the morning — same sessions, same scrollback, like the update had happened to a different computer."

— Grace Liu, backend engineer and Influxx user

The Shortcut That Looked Simpler on Paper

Before relocating a renamed copy of Influxx's own application binary, we tried the more obvious-looking fix: build the relocated daemon from a plain, generic Node.js runtime instead. On paper it's more minimal and more conventional than dragging along a renamed copy of the whole Electron application doing the same job.

In practice it introduced a regression small in engineering terms and impossible to ignore in user-facing ones: a visible console window would briefly flash on screen during terminal operations on Windows. It never showed up in a functional test, because it didn't break anything a test asserts on — it just made the product look broken at the exact moment a developer was watching it most closely. We reverted it and went back to a renamed copy of the application's own binary, which doesn't carry the same console-allocation behavior. Simpler in the codebase was not worth worse in front of an actual user.

How Small Can the Relocated Runtime Actually Be

Copying an entire runtime closure to a new location on every version update isn't free — it costs disk space and time, and that cost shouldn't be paid carelessly just because the fix works. So a dedicated internal investigation measured, rather than guessed, the minimal set of files actually required to boot a real Windows ConPTY session from a relocated copy of the daemon, testing which files were truly load-bearing and which were carried along out of habit. The result was a set of tiered configurations rather than one fixed answer:

  • A full configuration: every file the daemon could plausibly touch, the safe default with no functionality left to chance.
  • A reduced, no-GPU configuration: everything a fully functional terminal daemon needs, minus the files that only matter for GPU-accelerated rendering a background daemon never performs.
  • A further-trimmed minimal configuration: pared down to the smallest file set that still reliably booted and drove a real session under actual testing.

That's the difference between finding a fix and verifying how much of it was actually necessary. Copying files nobody needs still costs disk space and time on every update, for every Influxx user on Windows, for as long as nobody goes back and checks.

The Fix for Updates Can't Become a Bug for Uninstalls

Relocating the daemon solves the update problem but immediately raises a different one: if its files don't live in the install directory, the normal uninstall process — which mostly just deletes that directory — won't clean them up on its own, leaving an orphaned runtime sitting in a user's application-data directory indefinitely.

The uninstaller accounts for this, but has to carefully distinguish two operations that look similar from inside an installer script: a genuine, deliberate uninstall, and the in-place update that put the relocated daemon there to begin with. If the uninstall script deleted those files every time it ran, it would delete them during a routine update too — silently undoing the entire fix on every single update, forever. So it explicitly checks which operation is actually in progress before deciding whether the relocated files are supposed to go: delete them on a genuine uninstall, leave them alone during an update, because surviving an update is exactly what the relocation was built to do.

Testing a Failure You Can Only Trigger by Destroying a Real Install

None of this is worth much without a test that actually proves it, and this failure mode resists the usual kind of test. Verifying that a live session survives a Windows update means running a real installer through a real update-and-replace cycle and confirming the daemon and its sessions are still alive on the other side — genuinely letting an installer force-close processes and delete a real install directory, the exact destructive sequence this fix exists to survive.

That's not something to run against a developer's actual, permanent Influxx installation, and a unit test with mocked filesystem calls can't honestly stand in for it either — a mock will happily agree that deletion "succeeded" without ever proving the daemon it deleted was still holding a session open. So the scenario is validated by dedicated automated tests that run exclusively on disposable runners built and torn down for exactly this purpose: install Influxx for real, start a real session, trigger a real update, and confirm the session is still there afterward.

"This is my favorite kind of engineering story, because it's honest about the order things happened in. Nobody designed the daemon to survive a Windows update on day one, because nobody had a reason to think it needed to. Windows taught us that it did, and the response was rejecting a shortcut that caused a visible regression, measuring the actual minimal footprint instead of guessing at it, and making sure the fix for updates couldn't quietly become a bug for uninstalls. That's the standard we hold this kind of fix to."

— Priya Anand, VP of Engineering at ETAPX

Frequently Asked Questions

What exactly does a Windows update do that could kill a running Influxx session?

A typical Windows installer updates an app by force-closing every process whose image lives inside the install directory, deleting that directory outright, and writing the new version's files into its place. Influxx's background daemon used to run from inside that same directory by default, so a routine update could force-close it and delete its own running files in the same motion.

Does this affect Influxx on macOS or Linux?

No — it's a Windows-specific failure mode. Update mechanics on macOS and Linux don't assume it's safe to force-quit and delete an application's entire install directory out from under processes still running from it.

Where does the daemon actually run from now on Windows?

Outside the install directory entirely, in a versioned folder under the user's local application-data directory that the installer's update routine never touches, carrying its renamed executable, engine startup data, and native module tree with it. It also runs under a process name distinct from the main application's, so path-based and name-based process matching both miss it.

Why not just use a plain Node.js runtime for the relocated daemon?

We tried that first and reverted it, because a generic Node.js runtime caused a visible console window to briefly flash on screen during terminal operations on Windows. A renamed copy of the application's own binary doesn't produce that regression, so simpler in the codebase lost to better in front of the user.

Does relocating the daemon leave orphaned files behind after I uninstall Influxx?

No. The uninstaller explicitly checks whether it's running as part of a genuine uninstall or a routine in-place update before deciding whether to delete the relocated files, since deleting them during a routine update would undo the entire fix.

How do you actually test that a live session survives a Windows update?

With dedicated automated tests that run only on disposable, throwaway runners: install Influxx for real, start a real terminal session, run a real update through a real installer, and confirm the session is still alive afterward — something that only works by letting an installer genuinely delete a real install directory.

None of this was inevitable, and none of it stayed hypothetical once we understood how NSIS-based updates actually work on Windows. A daemon that never had to think about its own install directory found itself sitting squarely inside the one place a Windows update is allowed to destroy without asking, and the fix meant more than moving it: rejecting a shortcut that looked fine on paper, measuring the runtime down to the files that actually mattered, and making sure the same fix didn't quietly break uninstall in the other direction. Windows was the only one of our three platforms that ever asked this question. It got a real answer.