mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-04 10:42:23 +00:00
Status checks now queue a delayed check for each application, preview, service part, or database that goes from up to exited. After 2 minutes it sends the "Resource status changes" notification if the resource is still stopped, no deployment runs, and Coolify did not stop it. Each resource sends at most one notification in 15 minutes. Closes #9493
103 lines
3.7 KiB
PHP
103 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace App\Actions\Application;
|
|
|
|
use App\Actions\Server\CleanupDocker;
|
|
use App\Events\ApplicationStopFailed;
|
|
use App\Events\ServiceStatusChanged;
|
|
use App\Jobs\NotifyResourceStoppedJob;
|
|
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
|
|
{
|
|
NotifyResourceStoppedJob::expectStop($application, $application->settings->stopGracePeriodSeconds());
|
|
$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;
|
|
}
|
|
}
|