Skip to content

Add a verified deploy script for the worker - #30

Merged
brocla merged 2 commits into
mainfrom
deploy-script
Sep 11, 2026
Merged

Add a verified deploy script for the worker#30
brocla merged 2 commits into
mainfrom
deploy-script

Conversation

@brocla

@brocla brocla commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Replaces the manual redeploy — eight commands in an elevated shell — with scripts\Deploy-FileMill.ps1.

Why

The manual sequence has three traps:

  • The supervisor has to be stopped before the worker, or it relaunches the worker into the port you are trying to free.
  • Windows will not let a running executable be overwritten.
  • Start-ScheduledTask is a silent no-op while the task is still marked running (MultipleInstances IgnoreNew), so a missed check leaves the worker down.

How it avoids them

The supervisor is left running. Windows will not overwrite a running exe but it will rename one, so a deploy is:

rename bin\filemill.exe -> bin\filemill.<old version>.exe   (the rollback copy)
move   the new build    -> bin\filemill.exe
stop   the worker; the supervisor relaunches it into the new build

Downtime is a single worker restart and Task Scheduler is never touched.

Verification and rollback

Nothing is taken from an exit code alone:

  • the new binary must report its version before anything is swapped
  • the old worker must actually be gone, and a new one must appear
  • the new version must reach filemill.log

If any of that fails, the previous binary goes back, the build that failed is kept as bin\filemill.failed.exe, the log tail is printed so the cause is visible, and the script exits non-zero. It refuses to run unelevated (the worker runs in session 0) and refuses a dirty working tree unless -AllowDirty is passed. Worker processes are matched by full executable path, so another checkout's worker is never touched.

Tests

scripts\Test-DeployFileMill.ps1 runs the deploy against a stub worker and stub supervisor in a temp directory: one good build, and one that exits at startup to prove the rollback and the failure report. 11 checks, no elevation, no modules, and it cannot reach the installed service.

Build-FileMill.ps1 gains -Output so the deploy can build to a staging name instead of the running binary.

Scope

Operations tooling only. FileMill's Go code is untouched and CI is unchanged.

🤖 Generated with Claude Code

Kevin Brown and others added 2 commits September 11, 2026 16:51
Deploying was eight manual commands in an elevated shell, with three traps:
the supervisor has to be stopped before the worker or it resurrects it, a
running exe cannot be overwritten, and Start-ScheduledTask is a silent no-op
while the task is still marked running.

Deploy-FileMill.ps1 avoids all three by leaving the supervisor alone. Windows
will not overwrite a running executable but will rename one, so the running
binary is renamed aside (becoming the rollback copy), the new build moves into
its place, and stopping the worker is enough — the supervisor relaunches it
into the new build. Downtime is one restart and Task Scheduler is untouched.

Nothing is assumed from an exit code: the new binary must report its version,
the old worker must be gone, a new one must appear, and the new version must
reach filemill.log. Otherwise the previous binary goes back, the log tail is
printed, and it exits non-zero. Worker processes are matched by full path, so
a second checkout is never touched.

Test-DeployFileMill.ps1 runs it against a stub worker and stub supervisor in a
temp directory: one good build, and one that exits at startup to prove the
rollback. It needs no elevation and no modules.

Build-FileMill.ps1 gains -Output so the deploy can build to a staging name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The deploy script failed on its first real run, in the elevated 5.1 window it
is meant for, while passing the harness under pwsh 7. Two 5.1 differences, both
of which the harness now guards:

- A string containing an em dash. 5.1 reads a file with no byte-order mark as
  ANSI, so the em dash decodes to three characters, one of which is a smart
  quote - and PowerShell accepts smart quotes as string delimiters. It opened a
  string that never closed and the whole file stopped parsing. The scripts are
  ASCII-only now, and the harness enforces it.

- .Count on the result of Get-Workers. PowerShell unwraps a one-element array
  on return, and 5.1 answers $null when a lone CimInstance is asked for .Count
  (it looks for a CIM property of that name). Every worker check therefore read
  as "no worker running", which in the deploy would mean swapping the binary
  and never restarting the worker. Every call site wraps in @() now.

The harness parses both scripts with both shells before running anything, and
its waits report what they saw when they give up - polls made, the path
queried, and the process list - which is what finally identified the second
bug. It must be run under both shells; only 5.1 showed either of these.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@brocla
brocla merged commit 4820d80 into main Sep 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant