Skip to content

feat(autoupdate/compose): implement docker compose aware update logic#1875

Open
spupuz wants to merge 16 commits intogetarcaneapp:mainfrom
spupuz:feat/compose-update-logic
Open

feat(autoupdate/compose): implement docker compose aware update logic#1875
spupuz wants to merge 16 commits intogetarcaneapp:mainfrom
spupuz:feat/compose-update-logic

Conversation

@spupuz
Copy link
Contributor

@spupuz spupuz commented Feb 24, 2026

image

Container Update Flow: Logic and Scenarios

Arcane's new update architecture explicitly divides the update logic based on the nature of the container (Standalone vs Docker Compose) and acts intelligently to minimize downtime.

There are three main actors in this logic:

  1. User Setting: The useComposeUpdate flag in Local Docker -> Settings.
  2. Manual Action: The "Update" button on individual containers or "Redeploy/Update" on projects.
  3. Auto-Updater: The background system job (scheduled for automatic execution).

Here is how the code behaves in various scenarios:

Scenario 1: Standalone Container (Non-Compose)

This is the traditional behavior, unaltered by the new logic.

  • Manual Trigger / Auto-Update: The system recognizes that the container is not part of a project (absence of the com.docker.compose.project label).
  • Executed Flow:
    1. docker stop [id]
    2. docker rm -f [id]
    3. docker run ... (Recreates the container parsing the original configuration).

Scenario 2: Container belonging to a Compose Project

In this scenario, Arcane enters the ComposeAware branch. The behavior depends on the global setting configured by the user.

Sub-Scenario 2A: useComposeUpdate = false (Disabled)

The user has decided not to use native Docker Compose commands for updates.

  • Action: Arcane ignores the container's Compose origin and tries to restart it as if it were Standalone (Stop -> Rm -> Create).
  • Note: This can cause issues with dynamically generated networks and volumes by Compose, but guarantees backward compatibility with the pre-update-logic era.

Sub-Scenario 2B: useComposeUpdate = true (Enabled)

The user has enabled native updates. Arcane detects the project label.

If the Update is invoked by the "Auto-Update" Job (Background)

Arcane must prevent downtime and restart exclusively what is strictly necessary, and only if the remote image has a truly divergent hash.

  • Executed Flow:
    1. The DB signals that one or more project containers have a pending update.
    2. Arcane groups all containers marked for update based on their project name (avoiding duplicate pulls).
    3. For each group, it calls UpdateProjectServices:
      • The exact Service Name (e.g., web, db) is isolated from the affected container.
      • Executes docker compose pull [service_names...] (updates the image only for the services needing the update).
      • Executes a trick: docker stop && docker rm (or docker compose stop) on the single service to force its recreation, ensuring partial downtime only for the updating service.
      • Executes docker compose up -d [service_names...] to bring it back up, automatically reattaching it to networks/volumes and dependencies.

If the Update is manually invoked by the "Redeploy/Update" button in the "Projects" UI

Arcane uses a brute force approach, since it expects the user to know what they are doing or they are explicitly forcing a reload of the entire project configuration, regardless of the Image Poller.

  • Executed Flow:
    1. No preventive hash checks (it doesn't matter if the image is already up-to-date, it skips nothing).
    2. Enters UpdateProjectServices without service limitations.
    3. Executes docker compose pull (downloads layers if there are new ones online for any service).
    4. Executes docker compose up -d (Docker recreates only the containers whose configuration or image has mutated. The intact ones will remain Up without downtime).

Resiliency of Auto-Update (Hash Checks)

The Auto-Update system prevents unnecessary downtime by implementing double security checks:

  1. Before proceeding with any mechanics described above, the verification chain is instantiated via the ApplyPending method.
  2. Arcane extracts the Local Digest SHA256 of the image currently bound to the containers associated with "Pending" records.
  3. Requests the Remote Digest SHA256 of the target image on the fly from the Internet.
  4. If the Digest matches (Local == Remote): the routine is bypassed. A log "status":"skipped", "error":"image already up to date" is registered, and the container remains alive and unchanged. The green checkmark ✅ appears in the Updates column.
  5. If the Digest does not match: the Update pipeline (Standalone or ComposeAware) is officially authorized, and the container is updated.

Disclaimer Greptiles Reviews use AI, make sure to check over its work.

To better help train Greptile on our codebase, if the comment is useful and valid Like the comment, if its not helpful or invalid Dislike

Greptile Summary

This PR implements Docker Compose-aware container updates by adding a new useComposeUpdate setting that enables native docker compose pull/stop/up commands for compose project containers instead of standalone container restart logic.

Key changes:

  • Added UpdateProjectServices method to handle selective service updates within compose projects
  • Modified UpdateSingleContainer and restartContainersUsingOldIDs to detect compose containers and route them through project-based updates when the setting is enabled
  • Added ComposePull and ComposeStop helper functions to support the compose update workflow
  • Correctly uses the new pruneImageIDsWithInUseSetInternal method signature with nil second parameter (the method handles this gracefully)
  • Frontend adds UI toggle for the new setting with clear description

Minor issues:

  • Extra blank lines in updater_service.go (style)
  • Inconsistent defer error handling pattern in new cmds.go functions (style)

Confidence Score: 4/5

  • This PR is safe to merge with only minor style issues
  • The implementation is solid with proper error handling, fallback logic, and nil-safe method signatures. The title accurately reflects the change (using new method signature). Only minor style inconsistencies were found (extra blank lines and inconsistent defer patterns), which don't affect functionality.
  • No files require special attention - the style issues are trivial

Important Files Changed

Filename Overview
backend/internal/services/updater_service.go Adds compose-aware update logic with proper fallback to standalone updates; includes extra blank lines at line 395-396
backend/pkg/projects/cmds.go Adds ComposePull and ComposeStop functions; inconsistent defer error handling with Close()
backend/internal/services/project_service.go Adds GetProjectByComposeName and UpdateProjectServices methods; clean implementation with proper error handling

Last reviewed commit: 2354c8b

@spupuz spupuz requested a review from a team February 24, 2026 09:59
@spupuz spupuz changed the title fix(updater): use new pruneImageIDsWithInUseSetInternal method signature eat(autoupdate/compose): implement docker compose aware update logic Feb 24, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@spupuz spupuz changed the title eat(autoupdate/compose): implement docker compose aware update logic feat(autoupdate/compose): implement docker compose aware update logic Feb 24, 2026
@spupuz
Copy link
Contributor Author

spupuz commented Feb 24, 2026

image

@kmendell these are failing cause are going in timeout... i don't know ho to solve them

@spupuz
Copy link
Contributor Author

spupuz commented Feb 25, 2026

@kmendell let me know if you can do something

Copy link
Member

@kmendell kmendell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few things i found, but im still confused on how this is different fomr the updater depends on. When the updater (currently) runs on a conatnier its copys its exact config, and then creates a new container with that exact config labels, networks, everything, so im not sure what this solves exactly.

@spupuz
Copy link
Contributor Author

spupuz commented Feb 27, 2026

@kmendell let me know if you can do something

Few things i found, but im still confused on how this is different fomr the updater depends on. When the updater (currently) runs on a conatnier its copys its exact config, and then creates a new container with that exact config labels, networks, everything, so im not sure what this solves exactly.

Hi kmendell, that's a fair question. You're right that Arcane already attempts to clone the container config, but the new Compose-aware methodology is fundamentally different in terms of how and why it operates.

The key differences are:

Native Orchestration vs Manual Reconstruction: The current standalone methodology manually reconstructs a docker run command by inspecting the container. This is a "best-effort" reconstruction that can be fragile with complex configurations. The new methodology uses the native Docker Compose engine as the source of truth. By calling docker compose pull/up, we offload the orchestration complexity to Docker itself, which is significantly more robust.

Selective & Intelligent Service Updates: While the standalone flow has a custom dependency sorter (in sorter.go), it's still a manual simulation. Using native Compose allows us to run docker compose up -d [services], letting Docker intelligently decide which containers actually need a restart based on image or config divergence. This prevents "blind" restarts of the entire chain if nothing has changed.

Optimized Downtime: Standalone updates always follow a stop -> rm -> run cycle, causing guaranteed downtime. The Compose-aware flow uses RecreateDiverged logic, meaning Docker only recreates what is strictly necessary. For the background Auto-Updater, we've also added explicit SHA256 digest comparisons before pulling to minimize any unnecessary activity.

Resource Integrity: Compose-managed networks, aliases, and volumes are managed more reliably by the native engine than by Arcane's manual reconstruction logic. This ensures that a project container always comes back up exactly as the user (or the project) defined it.

In short: we are moving from Arcane simulating an update to Arcane delegating it to the official tool that manages the project.

@github-actions
Copy link

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

@github-actions
Copy link

github-actions bot commented Mar 3, 2026

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

@spupuz
Copy link
Contributor Author

spupuz commented Mar 3, 2026

@kmendell i'm i supposed to do something or are you fixing the conflicts?

@kmendell
Copy link
Member

kmendell commented Mar 5, 2026

yes youll have to fix the conflicts im too busy at the moment to do that and finish up the other stuff.

@spupuz spupuz force-pushed the feat/compose-update-logic branch from 63e3536 to 8024311 Compare March 5, 2026 14:33
@spupuz
Copy link
Contributor Author

spupuz commented Mar 5, 2026

@kmendell i should have fixed the merge problems but still the E2E test are going long.

@spupuz spupuz requested a review from kmendell March 5, 2026 20:02
@github-actions
Copy link

github-actions bot commented Mar 6, 2026

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

@github-actions
Copy link

github-actions bot commented Mar 8, 2026

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

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.

2 participants