From cfca1558906f3fb52ea0da4a09853bab3193231e Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 25 Aug 2026 11:50:33 +0200 Subject: [PATCH] fix(deployments): honor stop grace period in compose services (#11498) --- app/Jobs/ApplicationDeploymentJob.php | 4 + ...plicationDeploymentStopGracePeriodTest.php | 85 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 tests/Unit/ApplicationDeploymentStopGracePeriodTest.php diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 451d4377c..1b0ccb218 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -3301,6 +3301,10 @@ private function generate_compose_file() // Always use .env file $docker_compose['services'][$this->container_name]['env_file'] = ['.env']; + if ($this->application->settings->stop_grace_period !== null) { + $docker_compose['services'][$this->container_name]['stop_grace_period'] = $this->application->settings->stopGracePeriodSeconds().'s'; + } + // Only add Coolify healthcheck if no custom HEALTHCHECK found in Dockerfile // If custom_healthcheck_found is true, the Dockerfile's HEALTHCHECK will be used // If healthcheck is disabled, no healthcheck will be added diff --git a/tests/Unit/ApplicationDeploymentStopGracePeriodTest.php b/tests/Unit/ApplicationDeploymentStopGracePeriodTest.php new file mode 100644 index 000000000..4aa45c043 --- /dev/null +++ b/tests/Unit/ApplicationDeploymentStopGracePeriodTest.php @@ -0,0 +1,85 @@ + 'Stop Grace Period Team', + 'personal_team' => false, + 'show_boarding' => false, + ]); + $project = Project::create([ + 'name' => 'Stop Grace Period Project', + 'team_id' => $team->id, + ]); + $environment = Environment::where('project_id', $project->id)->firstOrFail(); + $server = Server::factory()->create(['team_id' => $team->id]); + $destination = $server->standaloneDockers()->firstOrFail(); + $application = Application::factory()->create([ + 'environment_id' => $environment->id, + 'destination_id' => $destination->id, + 'destination_type' => StandaloneDocker::class, + 'build_pack' => 'nixpacks', + ]); + $application->settings()->update(['stop_grace_period' => $stopGracePeriod]); + + $queue = Mockery::mock(ApplicationDeploymentQueue::class)->makePartial(); + $queue->status = 'queued'; + $queue->shouldReceive('refresh')->once()->andReturnSelf(); + + $job = new TestableStopGracePeriodDeploymentJob; + $reflection = new ReflectionClass(ApplicationDeploymentJob::class); + + foreach ([ + 'application' => $application->fresh(), + 'application_deployment_queue' => $queue, + 'destination' => $destination, + 'server' => $server, + 'mainServer' => $server, + 'pull_request_id' => 0, + 'container_name' => 'stop-grace-period-app', + 'production_image_name' => 'example/app:latest', + 'deployment_uuid' => 'deployment-uuid', + 'workdir' => '/artifacts/stop-grace-period-app', + 'configuration_dir' => '/data/coolify/applications/test', + 'saved_outputs' => new Collection, + ] as $property => $value) { + $reflection->getProperty($property)->setValue($job, $value); + } + + $reflection->getMethod('generate_compose_file')->invoke($job); + $compose = Yaml::parse($reflection->getProperty('docker_compose')->getValue($job)); + + return $compose['services']['stop-grace-period-app']; +} + +it('adds an explicitly configured stop grace period to generated compose services', function () { + expect(generateComposeServiceWithStopGracePeriod(700)) + ->toHaveKey('stop_grace_period', '700s'); +}); + +it('omits the stop grace period from generated compose services when it is not configured', function () { + expect(generateComposeServiceWithStopGracePeriod(null)) + ->not->toHaveKey('stop_grace_period'); +});