feat(deployments): rebuild from source on rollback for git projects#155
Merged
Conversation
Rollback previously reused the target deployment's stored Docker image. That path is fragile: - The nightly cleanup prunes dangling images after ~7 days, so rolling back to anything older fails with "image no longer exists locally". - It sets health_check_path=None, routing traffic before the container is confirmed listening. - It can't reconstruct static deployments (the prior image lacks a server runtime). For git-sourced projects that carry a commit/branch, rollback now re-runs the full build pipeline at the target deployment's commit via trigger_pipeline, instead of reusing the image. This always works (no dependency on a surviving image), goes through the same build + health-check pipeline as a normal deploy, and rebuilds static bundles correctly. Non-git projects (docker_image / static_files / manual without a git ref) have no source to rebuild and keep the existing image-reuse path unchanged. Mechanism: GitPushEventJob gains an optional rollback_from_deployment_id (#[serde(default)] for back-compat). When set, process_git_push_event marks the created deployment is_rollback / rolled_back_from_id and tags context_vars with trigger=rollback. trigger_pipeline delegates to a new trigger_pipeline_inner that carries the marker; the public signature is unchanged. Tests: new test_rollback_rebuilds_from_source_for_git_projects asserts a git deployment with a commit takes the rebuild path (no synchronous image-reuse row). Existing test_rollback_to_deployment (no git ref) still exercises and passes the image-reuse path.
… only when gone The git-rollback path rebuilt from source unconditionally, even when the target deployment's image was still in the local Docker cache. Reusing a present image is near-instant and byte-identical to what we're rolling back to, so gate the rebuild on image availability: reuse when the image exists, fall back to rebuild-from-source only when it's pruned or the preset is static (no runnable image). Non-git projects are unchanged. Reworks the rollback tests to cover both branches (image present -> reuse, image missing -> rebuild) and corrects the CHANGELOG wording.
…urce # Conflicts: # CHANGELOG.md
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.
Summary
Rollback previously reused the target deployment's stored Docker image unconditionally. That approach is fragile, with three documented failure modes:
Docker image '...' no longer exists locally.This PR makes rollback prefer image reuse when the image is still local, and fall back to rebuild-from-source only when it isn't:
Non-git projects (
docker_image/static_files/manualwithout a git ref) have no source to rebuild, so they keep the existing image-reuse path unchanged.Mechanism
GitPushEventJobgains an optionalrollback_from_deployment_id(#[serde(default)]for back-compat with in-flight queued jobs).rollback_to_deploymentprobesdeployer.image_exists(...)(static presets count as "not present"); a git project rebuilds from source only whensource_type == Git && has_git_ref && !image_present. Otherwise it falls through to the unchanged image-reuse path.process_git_push_eventmarks the created deploymentis_rollback/rolled_back_from_idand tagscontext_varswithtrigger=rollback/source=rebuild_from_source, so the UI/history show it as a rollback.trigger_pipeline's public signature is unchanged — it delegates to a privatetrigger_pipeline_innerthat carries the marker. All otherGitPushEventJobconstruction sites passNone.Testing
Unit (real Postgres):
test_rollback_reuses_local_image_for_git_projects— git project + image present → image-reuse (synchronous new row, different id).test_rollback_rebuilds_from_source_when_image_missing— git project + pruned image → rebuild (GitPushEvent enqueued, no synchronous row).test_rollback_fails_when_image_missing(non-git) andtest_rollback_to_deployment(non-git happy path) — unchanged behavior, still pass.temps-deploymentssuite: 388 passed,cargo check+clippy+fmtclean.End-to-end (live server, real GitHub repo + Docker images), project
sandbox-test-nextjs:Rollback: Image '...' exists locally, proceeding; new deploymentcompletedin 911 ms, image reused, no clone/build/GitPushEvent.docker rmiof the target's image:... target image is unavailable (image not in local cache) — rebuilding from source at commit ...; a GitPushEvent was enqueued, a new deployment (isRollback:true,source=rebuild_from_source) downloaded the source archive and built a fresh image via BuildKit.Notes
temps rollbackneeds no change — it calls the same endpoint.