diff --git a/.ai/lessons.md b/.ai/lessons.md index 33185493cb..c15a0558ec 100644 --- a/.ai/lessons.md +++ b/.ai/lessons.md @@ -45,6 +45,8 @@ - MCP tools that call REST routes remove response keys from `BuildsResponse::$sensitiveKeys` (for example `content`, `client_id`, `logs`) when the token has no `read:sensitive`, and `CallsRestApi::$blockedRestPaths` blocks some routes. Check both lists when you name the fields of a new API response or add an MCP tool for a route. +- To prove BuildKit cache behavior, use a new Dockerfile with a unique step for each experiment and repeat each build. Old cache records can make a changed input look cached. BuildKit keys `RUN` steps on the `--add-host` names and their order, but not on the IPs. + ## Verify the complete user flow - Do not use a passing unit test, a successful build, or a healthy process as proof for a reported UI failure. - Verify the exact live flow, persisted state, relevant logs, and queue state when they affect the result. diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 5c51791e5d..8a92fa8463 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -68,6 +68,12 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue */ private const HELPER_DOCKER_CONFIG = '/root/.docker'; + /** + * Name prefixes of the helpers that DatabaseBackupJob (S3 upload) and StartDatabaseImport + * (S3 download) run on a resource network for the duration of one backup or import. + */ + private const TEMPORARY_HELPER_CONTAINER_PREFIXES = ['backup-of-', 's3-restore-']; + /** * System CA bundles of the supported server distributions, in the order that Go checks them. * @@ -363,9 +369,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue /** * Build the --add-host flags for the containers on the destination network. * - * Build helper containers are named after their deployment uuid and only live for the - * duration of that deployment. BuildKit keys every RUN layer on the --add-host set, - * so letting one in gives the next build a different set and forces a full rebuild. + * BuildKit keys every RUN layer on the host names of the --add-host set (not on the IPs), so a + * container that joins or leaves the network between two builds forces a full rebuild. The set + * leaves out the short-lived containers: build helpers (named after their deployment uuid), + * rolling update containers, and the backup and S3 import helpers. It also leaves out the proxy, + * Sentinel, and the proxy error page containers: no build uses them, and Coolify recreates them. */ private function addHostFlags(Collection $containers): string { @@ -377,7 +385,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $ips = collect([]); foreach ($containers as $container) { $containerName = data_get($container, 'Name'); - if ($containerName === 'coolify-proxy') { + if (in_array($containerName, ['coolify-proxy', 'coolify-sentinel', Server::PROXY_ERROR_PAGE_CONTAINER], true)) { continue; } if (isGeneratedContainerName($containerName)) { @@ -386,6 +394,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue if ($buildHelperNames->contains($containerName)) { continue; } + if (str($containerName)->startsWith(self::TEMPORARY_HELPER_CONTAINER_PREFIXES)) { + continue; + } $containerIp = data_get($container, 'IPv4Address'); if ($containerName && $containerIp) { $ips->put($containerName, str($containerIp)->before('/')->value()); diff --git a/tests/Feature/ApplicationDeploymentAddHostsTest.php b/tests/Feature/ApplicationDeploymentAddHostsTest.php index f57ac02e35..ef345e8f10 100644 --- a/tests/Feature/ApplicationDeploymentAddHostsTest.php +++ b/tests/Feature/ApplicationDeploymentAddHostsTest.php @@ -34,3 +34,23 @@ it('keeps the --add-host set stable whether or not a build helper is running', f ->toBe(addHostFlagsFor([$database])) ->toBe('--add-host postgres-main:10.0.1.3'); }); + +it('keeps database backup and S3 import helpers out of --add-host', function () { + $database = ['Name' => 'postgres-main', 'IPv4Address' => '10.0.1.3/24']; + + expect(addHostFlagsFor([ + $database, + ['Name' => 'backup-of-bk7f2c9d0a1e4b5c6d7e8f9a0', 'IPv4Address' => '10.0.1.11/24'], + ['Name' => 's3-restore-k4b2x9q1', 'IPv4Address' => '10.0.1.12/24'], + ]))->toBe(addHostFlagsFor([$database])) + ->toBe('--add-host postgres-main:10.0.1.3'); +}); + +it('keeps the Coolify proxy, Sentinel, and error page containers out of --add-host', function () { + expect(addHostFlagsFor([ + ['Name' => 'coolify-proxy', 'IPv4Address' => '10.0.1.2/24'], + ['Name' => 'coolify-sentinel', 'IPv4Address' => '10.0.1.3/24'], + ['Name' => 'coolify-proxy-error-pages', 'IPv4Address' => '10.0.1.4/24'], + ['Name' => 'postgres-main', 'IPv4Address' => '10.0.1.5/24'], + ]))->toBe('--add-host postgres-main:10.0.1.5'); +});