mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-14 00:33:44 -04:00
- Do not ignore errors of the docker stop and rm commands, so a failed SSH call does not mark a running application as exited. - Log the failure and broadcast ApplicationStopFailed; the application page shows an error toast. Closes #11063 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
3.6 KiB
PHP
101 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Actions\Application;
|
|
|
|
use App\Actions\Server\CleanupDocker;
|
|
use App\Events\ApplicationStopFailed;
|
|
use App\Events\ServiceStatusChanged;
|
|
use App\Models\Application;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Lorisleiva\Actions\Concerns\AsAction;
|
|
|
|
class StopApplication
|
|
{
|
|
use AsAction;
|
|
|
|
public string $jobQueue = 'high';
|
|
|
|
public function handle(Application $application, bool $previewDeployments = false, bool $dockerCleanup = true, bool $resetRestartCount = true, bool $removeContainers = true): ?string
|
|
{
|
|
$containerPresent = ! $removeContainers;
|
|
$servers = collect([$application->destination->server]);
|
|
if ($application?->additional_servers?->count() > 0) {
|
|
$servers = $servers->merge($application->additional_servers);
|
|
}
|
|
$errors = [];
|
|
foreach ($servers as $server) {
|
|
try {
|
|
if (! $server->isFunctional()) {
|
|
$errors[] = "Server {$server->name} is not functional.";
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($server->isSwarm()) {
|
|
$containerPresent = false;
|
|
instant_remote_process(['docker stack rm '.escapeshellarg($application->uuid)], $server);
|
|
|
|
continue;
|
|
}
|
|
|
|
$containers = $previewDeployments
|
|
? getCurrentApplicationContainerStatus($server, $application, includePullrequests: true)
|
|
: getCurrentApplicationContainerStatus($server, $application, 0);
|
|
|
|
$containersToStop = $containers->pluck('Names')->toArray();
|
|
$timeout = $application->settings->stopGracePeriodSeconds();
|
|
|
|
foreach ($containersToStop as $containerName) {
|
|
$escapedContainerName = escapeshellarg($containerName);
|
|
$commands = [dockerStopCommand($timeout, $escapedContainerName, $server)];
|
|
if ($removeContainers) {
|
|
$commands[] = "docker rm -f {$escapedContainerName}";
|
|
}
|
|
|
|
try {
|
|
instant_remote_process(command: $commands, server: $server);
|
|
} catch (\Exception $e) {
|
|
$errors[] = $e->getMessage();
|
|
}
|
|
}
|
|
|
|
if ($removeContainers && $application->build_pack === 'dockercompose') {
|
|
$application->deleteConnectedNetworks();
|
|
}
|
|
|
|
if ($dockerCleanup) {
|
|
CleanupDocker::dispatchAfterStop($server);
|
|
}
|
|
} catch (\Exception $e) {
|
|
$errors[] = $e->getMessage();
|
|
}
|
|
}
|
|
$teamId = $application->environment->project->team->id;
|
|
if ($errors !== []) {
|
|
$message = implode(' ', $errors);
|
|
Log::warning('Failed to stop application', ['application_uuid' => $application->uuid, 'error' => $message]);
|
|
ApplicationStopFailed::dispatch($teamId, $application->uuid, $message);
|
|
|
|
return $message;
|
|
}
|
|
|
|
$status = [
|
|
'status' => 'exited',
|
|
'container_present' => $containerPresent,
|
|
];
|
|
if ($resetRestartCount) {
|
|
$status = array_merge($status, [
|
|
'restart_count' => 0,
|
|
'last_restart_at' => null,
|
|
'last_restart_type' => null,
|
|
'restart_limit_reached' => false,
|
|
]);
|
|
}
|
|
$application->update($status);
|
|
|
|
ServiceStatusChanged::dispatch($teamId);
|
|
|
|
return null;
|
|
}
|
|
}
|