feat(compose): transactional deployments with automatic rollback to last good release - #5182
Open
EngAbo3lia wants to merge 14 commits into
Open
feat(compose): transactional deployments with automatic rollback to last good release#5182EngAbo3lia wants to merge 14 commits into
EngAbo3lia wants to merge 14 commits into
Conversation
…eploy When a docker compose deploy fails mid up, running services could be left stopped or removed, taking the previous working deployment down. Wrap the deploy in a transaction: snapshot the current compose file and env file to .deploy-backup before applying changes; on failure, restore both files and re-run up -d (without --build) so the last successful deployment keeps serving traffic while the deployment itself still reports as failed.
Failed docker compose deploys previously killed running services: 'docker compose up -d --build' mutated the live namespace in place and a mid-deploy failure could leave containers stopped or removed. This makes compose deploys transactional (Vercel-style guarantee for stateful stacks): - backupCurrentDeployment(): snapshot the compose file and .env to .deploy-backup before the deploy flow touches them (raw/git sources rewrite these on every deploy). - getBuildComposeCommand(): on deploy failure, restore the snapshot and run 'up -d' without '--build' so the last working version keeps its containers up and serving; deployment still reports as failed. - After each successful deploy, persist a 'last-good' snapshot; rollback prefers it, so the last SUCCESSFUL deployment (not the last attempt) is what gets reinstated. Only applies to 'docker-compose' type (swarm handles its own rollback).
After a failed deploy that was auto-rolled-back, composeStatus was set to 'error', showing a red dot even though the last-good deployment was still running and serving traffic (Vercel shows the failed deployment in history but the service stays online). Emit __DOKPLOY_ROLLBACK_OK__ after a successful restore and set composeStatus to 'done' instead of 'error' when the marker is found, so the service card reflects the actually-served state. The failed deployment still shows as error in the deployments tab.
The service header now shows Vercel-style status under the service name: - green Live badge with the last successful deployment title - amber 'Deploying...' badge while a deployment runs - red 'Last deploy failed - live kept' badge when the latest deploy failed but the last successful one is still serving Refresh the deployments list every 5s so badges update in real time.
A failed deploy must never flip the service status, even if the rollback up-didn't run: as long as a previous successful deployment has a last-good snapshot, the service is considered live (green). Only when there has never been a successful deployment does the status go red.
- Status badges (Live/Deploying/failed) moved to the header's right
column above server badge; cleaner labels ('Live', 'Last deploy
failed') with tooltips instead of raw deployment titles.
- Domain URLs rendered as clickable chips under service name/appName:
enabled = green link, disabled = greyed strikethrough.
- Identity column: icon, name, mono appName with click-to-copy (Copy/Check icons), truncated description. - Status badges restyled with soft tinted borders; Live badge uses a pulsing emerald dot; 'Deploy failed' replaces verbose label. - Server badge, edit and delete actions merged into a single row. - Domain URLs moved to their own strip under the header with Globe/ ArrowUpRight icons; disabled domains render muted strikethrough.
…, permission-gated polling Greptile review fixes: - didRollbackSucceed now only reports success when the rollback actually ran to completion (ROLLBACK_OK_MARKER present in the deployment log). A leftover last-good snapshot file no longer marks the service as live, so failed or skipped restorations surface as error instead of silently claiming green. - rebuildCompose now snapshots the current compose file and .env before touching anything (backupCurrentDeployment), so a failed rebuild - even the first one after an upgrade, with no last-good snapshot - restores the pre-change files instead of leaving broken definitions on disk. - Compose service header: deployment and domain queries are now gated on the user's deployment.read / domain.read permissions (enabled + refetchInterval), so members without those permissions no longer fire denied polling requests every 5/10s. Also applies biome fixes (@ts-expect-error) to the kept @ts-ignore.
…ored The restore path swallowed failed file copies (cp ... || true), so a deploy whose rollback had nothing to restore could still emit __DOKPLOY_ROLLBACK_OK__ and mark the service live with the broken definition still on disk. Track copy success in RESTORE_FILES_OK (1 = a compose file and an env file were copied back) and require it for the marker: the marker is emitted only when both the restored files exist and 'docker compose up -d' succeeds.
- didRollbackSucceed now greps the marker as a line-exact match (^__DOKPLOY_ROLLBACK_OK__$), so user build/startup output containing the string can no longer spoof rollback success. - The .env restore is best-effort again: services with createEnvFile=false have no env backup, so an env copy failure no longer suppresses the marker when the compose definition was restored and 'up -d' succeeded. - Marker constant is now defined once (exported from builders/compose) and reused by the deploy services instead of being duplicated.
…ore when snapshots exist - The rollback marker is now echoed as __DOKPLOY_ROLLBACK_OK__:<deploymentId> and the log match is anchored to that exact line, so the constant alone printed by a compose build/container can no longer spoof a successful rollback (the deployment id is generated per deployment and unknown to service output). didRollbackSucceed and the build command thread the id. - The .env restore is best-effort only when no env snapshot exists (createEnvFile=false services). When a previous env snapshot is present and the restore copy fails, the marker is suppressed so the service is not marked live with an environment that differs from the last good one.
createEnvFile=true services always consume a generated .env: when the failed deploy overwrote it and no env snapshot is present, the rollback must not be declared successful even if the compose definition was restored. The marker is now gated whenever the service generates an env file, regardless of snapshot presence; env-less services keep the best-effort behavior.
backupCurrentDeployment previously converted a failed snapshot cp into a successful echo (|| echo), so a rebuild could rewrite the live definition with no guarantee that the previous release is recoverable. The backup now copies only when the source exists (missing source = first deploy, allowed) and exits with an error when a copy fails, aborting the deploy before any file is rewritten.
persistLastGood previously ignored failed copies (|| true), so a stale last-good could survive a persist failure and a later rollback would prefer it over the fresh pre-deployment backup, restoring an older definition than the last successful one. On persist failure the stale snapshot is now removed, forcing rollback to the fresh backup.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is this PR about?
Today, if a Docker Compose deployment fails (wrong image name, broken compose file, failed build), Dokploy can leave your running services down until you notice and manually redeploy. This PR fixes that: a failed deploy now rolls back automatically and your last working release keeps serving traffic, Vercel-style.
How it works
.envare backed up.docker compose up -dbrings the previous release back up. Each step is visible in the deployment log.UI improvements included
Scope: applies to
docker-composetype only. Stack type deployments keep their current behavior.Testing
Verified end-to-end on a local instance:
Checklist
Before submitting this PR, please make sure that:
canarybranch.Greptile Summary
This PR adds transactional Docker Compose deployments that preserve the current deployment, restore it after failed updates, and retain known-good artifacts for later recovery. It also adds permission-aware deployment and domain status information to the Compose service header.
Confidence Score: 5/5
The PR appears safe to merge.
No blocking failure remains.
Reviews (8): Last reviewed commit: "fix(compose): drop stale last-good snaps..." | Re-trigger Greptile
Context used (3)