Skip to content

feat: show a status panel while the web server updates - #36

Merged
agentHits merged 3 commits into
AgentHits-Devfrom
feat/update-status-panel
Oct 7, 2026
Merged

agentHits merged 3 commits into
AgentHits-Devfrom
feat/update-status-panel

Conversation

@agentHits

Copy link
Copy Markdown
Collaborator

Stacked on #35. Retarget to AgentHits-Dev after #35 is merged.

Problem

After "Update Server" -> "Confirm", the Web Server Update dialog only showed a spinner with one sentence. The admin could not tell whether the image was still downloading, whether the download failed, or how long Dokploy had been down while it restarted.

What

Server

  • New packages/server/src/services/web-server-update.ts: startServerUpdate(command) runs the update script in the background (as before, via spawnAsync("sh", ["-c", ...])) and tracks it in memory: phase (idle / pulling / updating / done / failed), startedAt, pulledAt, finishedAt, a short error, docker pull layer counts (total / downloaded / extracted) and the last 5 output lines. A second request while an update is running does not start another script.
  • getAgentHitsUpdateCommand / getOfficialUpdateCommand print a marker right after docker pull ... || exit 1, so the server knows when the pull finished. Pull-first, || exit 1 and the env args are unchanged.
  • settings.updateServer uses startServerUpdate; it still returns true.
  • New admin query settings.getServerUpdateStatus, classified as "read".
  • The status lives only in the process. It is lost on restart by design: a fresh idle status is also how the UI recognises the new process.

UI

  • UpdateStatusPanel (components/dashboard/settings/web-server/update-status-panel.tsx) is a pure view with props { progress, now }. It shows four steps (Downloading the new image, Restarting Dokploy, Starting the new version, Done). Each step has a done / active / pending / failed state, elapsed times, layer progress, a live downtime counter and a failure box with the last output lines.
  • The phase logic is pure in update-progress.ts. The dialog polls getServerUpdateStatus while the old server answers, switches to /api/health while Dokploy is down, then waits for the API to answer again (or 60 s of healthy /api/health) before the existing toast and reload.
  • Failures: the pull or docker service update fails, the server does not go down within 20 minutes, or it does not come back within 10 minutes after it stopped. The dialog then shows what failed and a Close button.
  • If the restart happens between two polls (for example, timers throttled in a background tab), an idle status after a seen job counts as done.

Checks

  • apps/dokploy: bunx tsc --noEmit passes. packages/server: bunx tsc --noEmit passes.
  • bunx vitest run --config __test__/vitest.config.ts __test__/settings/ __test__/security/: 33 files, 279 tests pass. New: web-server-update-status.test.ts (output parsing, phases, failures, no double start) and update-progress.test.ts (phase transitions, limits, step states). Updated: the router boundary tests, and the update command tests, which now also run the marker echo line through sh.
  • bunx biome check --write on the changed paths is clean.

Not checked

  • The panel has not been checked in a browser yet.
  • No real update was run against a server, so the docker pull output format (layer lines) has not been checked with the Docker version on the host. If the format differs, only the layer counter stays empty; phases still work through the marker and the exit code.
  • After the restart the UI does not check that the new process runs a newer version. A crash and restart of the old version during the pull would also read as "done". The page reload then shows the real state.

🤖 Generated with Claude Code

agentHits and others added 2 commits October 7, 2026 07:38
The dokploy service updates stop-first, so the swarm task pulled the new
4.4 GB image only after the old container had stopped. On dev that left
the panel down for 2 min 12 s (old container stopped 11:31:42, new one
started 11:33:54) and Traefik answered Bad Gateway.

Both update commands (AgentHits and official) now run `docker pull`
first and stop if it fails, so the downtime is only the restart. The
official update moves into getOfficialUpdateCommand to be testable.

The update dialog used to reload after a fixed 8 s once /api/health
answered. With the pull in front, the old server still answers then, so
the dialog now waits until the server has gone down once and is healthy
again (giving up after 20 minutes with an error).

The image list and the cleanup also missed images that swarm pulls by
digest: they have no tag, and `docker image ls` hides untagged images
unless `-a` is passed. The running image after a UI update was one of
them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After "Update Server" -> "Confirm" the dialog only showed a spinner and
one sentence, and during the restart the admin saw nothing useful.

The server now tracks the running update job in memory: the update
scripts print a marker once `docker pull` succeeded, and the new
startServerUpdate runs the script, follows its output and records the
phase (pulling, updating, done, failed), timestamps, docker pull layer
counts, the last few output lines and a short error. The admin-only
settings.getServerUpdateStatus query (classified as "read") exposes it.
The state is lost when Dokploy restarts, which is expected: a fresh
"idle" status is also how the UI recognises the new process. A second
update request while one is running does not start another script.

The dialog now renders UpdateStatusPanel, a props-driven view of four
steps (downloading the image, restarting Dokploy, starting the new
version, done) with done/active/pending/failed states, elapsed times
and a live downtime counter. The phase logic lives in update-progress.ts
as pure functions: the dialog polls the status query while the old
server answers, switches to /api/health while Dokploy is down, and
fails when the pull or the service update fails, when the server does
not go down within 20 minutes or does not come back within 10 minutes
after it stopped. A failed update keeps the dialog closable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@agentHits
agentHits changed the base branch from fix/update-prepull-image to AgentHits-Dev October 7, 2026 12:13
# Conflicts:
#	apps/dokploy/__test__/settings/docker-server-boundary.test.ts
#	apps/dokploy/__test__/settings/dokploy-image-cleanup.test.ts
#	apps/dokploy/components/dashboard/settings/web-server/update-webserver.tsx
#	apps/dokploy/server/api/routers/settings.ts
#	packages/server/src/services/settings.ts
@agentHits
agentHits merged commit e954886 into AgentHits-Dev Oct 7, 2026
8 checks passed
@agentHits
agentHits deleted the feat/update-status-panel branch October 7, 2026 12:28
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