mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
fix(deploy): keep the healthy new container when a rolling update fails late
Laravel runs failed() on a fresh copy of the job, so the in-memory newVersionIsHealthy flag was always false there and a failure after the old container stopped removed the only running container. Keep the flag in the cache, keyed by the deployment UUID. Closes #12253 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
2a7faa1210
commit
1bebdffaff
@@ -6,6 +6,9 @@ use App\Models\Application;
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
use Illuminate\Contracts\Queue\Job;
|
||||
use Illuminate\Queue\TimeoutExceededException;
|
||||
use Tests\TestCase;
|
||||
|
||||
uses(TestCase::class);
|
||||
|
||||
/**
|
||||
* Test to verify that deployment errors are properly logged with comprehensive details.
|
||||
@@ -91,6 +94,7 @@ it('logs comprehensive error details when failed() is called', function () {
|
||||
$containerNameProperty = $reflection->getProperty('container_name');
|
||||
$containerNameProperty->setAccessible(true);
|
||||
$containerNameProperty->setValue($job, 'test-container');
|
||||
$reflection->getProperty('deployment_uuid')->setValue($job, 'error-logging-test');
|
||||
|
||||
// Mock the failDeployment method to prevent errors
|
||||
$job->shouldReceive('failDeployment')->andReturn();
|
||||
@@ -197,6 +201,7 @@ it('handles exceptions with no message gracefully', function () {
|
||||
$containerNameProperty = $reflection->getProperty('container_name');
|
||||
$containerNameProperty->setAccessible(true);
|
||||
$containerNameProperty->setValue($job, 'test-container');
|
||||
$reflection->getProperty('deployment_uuid')->setValue($job, 'error-logging-test');
|
||||
|
||||
$job->shouldReceive('failDeployment')->andReturn();
|
||||
$job->shouldReceive('execute_remote_command')->andReturn();
|
||||
@@ -288,6 +293,7 @@ it('logs error code 0 correctly', function () {
|
||||
$containerNameProperty = $reflection->getProperty('container_name');
|
||||
$containerNameProperty->setAccessible(true);
|
||||
$containerNameProperty->setValue($job, 'test-container');
|
||||
$reflection->getProperty('deployment_uuid')->setValue($job, 'error-logging-test');
|
||||
|
||||
$job->shouldReceive('failDeployment')->andReturn();
|
||||
$job->shouldReceive('execute_remote_command')->andReturn();
|
||||
@@ -393,6 +399,7 @@ it('logs the configured timeout when the deployment times out', function () {
|
||||
|
||||
$containerNameProperty = $reflection->getProperty('container_name');
|
||||
$containerNameProperty->setValue($job, 'test-container');
|
||||
$reflection->getProperty('deployment_uuid')->setValue($job, 'error-logging-test');
|
||||
|
||||
$job->shouldReceive('failDeployment')->andReturn();
|
||||
$job->shouldReceive('execute_remote_command')->andReturn();
|
||||
|
||||
@@ -4,11 +4,14 @@ use App\Jobs\ApplicationDeploymentJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationDeploymentQueue;
|
||||
use App\Models\ApplicationSetting;
|
||||
use Tests\TestCase;
|
||||
|
||||
uses(TestCase::class);
|
||||
|
||||
/**
|
||||
* @return array<int, array<int|string, mixed>>
|
||||
*/
|
||||
function runFailedDeploymentCleanup(bool $consistentContainerName, ?string $customInternalName, int $pullRequestId, bool $newVersionIsHealthy = false): array
|
||||
function runFailedDeploymentCleanup(bool $consistentContainerName, ?string $customInternalName, int $pullRequestId): array
|
||||
{
|
||||
$settings = new ApplicationSetting;
|
||||
$settings->setRawAttributes([
|
||||
@@ -36,8 +39,8 @@ function runFailedDeploymentCleanup(bool $consistentContainerName, ?string $cust
|
||||
$reflection->getProperty('application_deployment_queue')->setValue($job, $queue);
|
||||
$reflection->getProperty('application')->setValue($job, $application);
|
||||
$reflection->getProperty('pull_request_id')->setValue($job, $pullRequestId);
|
||||
$reflection->getProperty('deployment_uuid')->setValue($job, 'cleanup-test-deployment');
|
||||
$reflection->getProperty('container_name')->setValue($job, 'new-container-20261001T120000');
|
||||
$reflection->getProperty('newVersionIsHealthy')->setValue($job, $newVersionIsHealthy);
|
||||
|
||||
$job->failed(new RuntimeException('Health check failed'));
|
||||
|
||||
@@ -62,14 +65,3 @@ it('keeps the running container when consistent container names are enabled', fu
|
||||
it('keeps the running container for pull request deployments', function () {
|
||||
expect(runFailedDeploymentCleanup(consistentContainerName: false, customInternalName: 'my-api', pullRequestId: 12))->toBeEmpty();
|
||||
});
|
||||
|
||||
it('keeps the new container when the deployment fails after the new container became healthy', function () {
|
||||
expect(runFailedDeploymentCleanup(consistentContainerName: false, customInternalName: null, pullRequestId: 0, newVersionIsHealthy: true))->toBeEmpty();
|
||||
});
|
||||
|
||||
it('removes the new container when the deployment fails before the new container became healthy', function () {
|
||||
$remoteCommands = runFailedDeploymentCleanup(consistentContainerName: false, customInternalName: null, pullRequestId: 0, newVersionIsHealthy: false);
|
||||
|
||||
expect($remoteCommands)->toHaveCount(1)
|
||||
->and($remoteCommands[0][0])->toContain('new-container-20261001T120000');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user