diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e8f213b16..912b790f0 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -43,10 +43,10 @@ class Kernel extends ConsoleKernel } else { // Instance Jobs $schedule->command('horizon:snapshot')->everyFiveMinutes(); - $schedule->command('cleanup:unreachable-servers')->daily(); + $schedule->command('cleanup:unreachable-servers')->cron($settings->server_cleanup_frequency)->onOneServer(); $schedule->job(new PullCoolifyImageJob)->cron($settings->update_check_frequency)->onOneServer(); $schedule->job(new PullTemplatesFromCDN)->cron($settings->update_check_frequency)->onOneServer(); - $schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer(); + $schedule->job(new CleanupInstanceStuffsJob)->cron($settings->server_cleanup_frequency)->onOneServer(); $this->schedule_updates($schedule); // Server Jobs @@ -56,7 +56,7 @@ class Kernel extends ConsoleKernel $this->check_scheduled_tasks($schedule); $schedule->command('cleanup:database --yes')->daily(); - $schedule->command('uploads:clear')->everyTwoMinutes(); + $schedule->command('uploads:clear')->cron($settings->server_cleanup_frequency)->onOneServer(); } } @@ -66,7 +66,14 @@ class Kernel extends ConsoleKernel $servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4'); foreach ($servers as $server) { if ($server->isSentinelEnabled()) { - $schedule->job(new PullSentinelImageJob($server))->cron($settings->update_check_frequency)->onOneServer(); + $schedule->job(function () use ($server) { + $sentinel_found = instant_remote_process(['docker inspect coolify-sentinel'], $server, false); + $sentinel_found = json_decode($sentinel_found, true); + $status = data_get($sentinel_found, '0.State.Status', 'exited'); + if ($status !== 'running') { + PullSentinelImageJob::dispatch($server); + } + })->cron($settings->update_check_frequency)->onOneServer(); } $schedule->job(new PullHelperImageJob($server))->cron($settings->update_check_frequency)->onOneServer(); } @@ -87,6 +94,7 @@ class Kernel extends ConsoleKernel private function check_resources($schedule) { + $settings = InstanceSettings::get(); if (isCloud()) { $servers = $this->all_servers->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended', false)->where('ip', '!=', '1.2.3.4'); $own = Team::find(0)->servers; @@ -96,7 +104,7 @@ class Kernel extends ConsoleKernel } foreach ($servers as $server) { $schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer(); - $schedule->job(new DockerCleanupJob($server))->everyTenMinutes()->onOneServer(); + $schedule->job(new DockerCleanupJob($server))->cron($settings->server_cleanup_frequency)->onOneServer(); } } @@ -107,7 +115,7 @@ class Kernel extends ConsoleKernel return; } foreach ($scheduled_backups as $scheduled_backup) { - if (! $scheduled_backup->enabled) { + if (!$scheduled_backup->enabled) { continue; } if (is_null(data_get($scheduled_backup, 'database'))) { @@ -139,7 +147,7 @@ class Kernel extends ConsoleKernel $service = $scheduled_task->service; $application = $scheduled_task->application; - if (! $application && ! $service) { + if (!$application && !$service) { ray('application/service attached to scheduled task does not exist'); $scheduled_task->delete(); @@ -166,7 +174,7 @@ class Kernel extends ConsoleKernel protected function commands(): void { - $this->load(__DIR__.'/Commands'); + $this->load(__DIR__ . '/Commands'); require base_path('routes/console.php'); } diff --git a/app/Jobs/DockerCleanupJob.php b/app/Jobs/DockerCleanupJob.php index 5010263ae..6c5e22b0a 100644 --- a/app/Jobs/DockerCleanupJob.php +++ b/app/Jobs/DockerCleanupJob.php @@ -12,6 +12,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Log; +use Cron\CronExpression; class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue { @@ -21,39 +22,44 @@ class DockerCleanupJob implements ShouldBeEncrypted, ShouldQueue public int|string|null $usageBefore = null; - public function __construct(public Server $server) {} + public function __construct(public Server $server) + { + } public function handle(): void { try { - if (! $this->server->isFunctional()) { + if (!$this->server->isFunctional()) { return; } - if ($this->server->settings->is_force_cleanup_enabled) { - Log::info('DockerCleanupJob force cleanup on '.$this->server->name); - CleanupDocker::run(server: $this->server, force: true); - + if ($this->server->settings->force_server_cleanup) { + $cronExpression = $this->server->settings->server_cleanup_frequency; + $cron = new CronExpression($cronExpression); + if ($cron->isDue()) { + Log::info('DockerCleanupJob force cleanup on ' . $this->server->name); + CleanupDocker::run(server: $this->server, force: true); + } return; } $this->usageBefore = $this->server->getDiskUsage(); if (str($this->usageBefore)->isEmpty() || $this->usageBefore === null || $this->usageBefore === 0) { - Log::info('DockerCleanupJob force cleanup on '.$this->server->name); + Log::info('DockerCleanupJob force cleanup on ' . $this->server->name); CleanupDocker::run(server: $this->server, force: true); return; } - if ($this->usageBefore >= $this->server->settings->cleanup_after_percentage) { + if ($this->usageBefore >= $this->server->settings->server_cleanup_threshold) { CleanupDocker::run(server: $this->server, force: false); $usageAfter = $this->server->getDiskUsage(); if ($usageAfter < $this->usageBefore) { - $this->server->team?->notify(new DockerCleanup($this->server, 'Saved '.($this->usageBefore - $usageAfter).'% disk space.')); - Log::info('DockerCleanupJob done: Saved '.($this->usageBefore - $usageAfter).'% disk space on '.$this->server->name); + $this->server->team?->notify(new DockerCleanup($this->server, 'Saved ' . ($this->usageBefore - $usageAfter) . '% disk space.')); + Log::info('DockerCleanupJob done: Saved ' . ($this->usageBefore - $usageAfter) . '% disk space on ' . $this->server->name); } else { - Log::info('DockerCleanupJob failed to save disk space on '.$this->server->name); + Log::info('DockerCleanupJob failed to save disk space on ' . $this->server->name); } } else { - Log::info('No need to clean up '.$this->server->name); + Log::info('No need to clean up ' . $this->server->name); } } catch (\Throwable $e) { ray($e->getMessage()); diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php index 8d8cf983d..963df3f4d 100644 --- a/app/Livewire/Server/Form.php +++ b/app/Livewire/Server/Form.php @@ -46,7 +46,7 @@ class Form extends Component 'wildcard_domain' => 'nullable|url', 'server.settings.is_server_api_enabled' => 'required|boolean', 'server.settings.force_server_cleanup' => 'required|boolean', - 'server.settings.server_cleanup_cron' => 'required_if:server.settings.force_server_cleanup,true', + 'server.settings.server_cleanup_frequency' => 'required_if:server.settings.force_server_cleanup,true', 'server.settings.server_cleanup_threshold' => 'required|integer|min:1|max:100', ]; @@ -73,7 +73,19 @@ class Form extends Component public function mount() { $this->wildcard_domain = $this->server->settings->wildcard_domain; - $this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage; + $this->server->settings->server_cleanup_threshold = $this->server->settings->server_cleanup_threshold; + $this->server->settings->server_cleanup_frequency = $this->server->settings->server_cleanup_frequency; + } + + public function updated($field) + { + if ($field === 'server.settings.server_cleanup_frequency') { + $frequency = $this->server->settings->server_cleanup_frequency; + if (empty($frequency) || !validate_cron_expression($frequency)) { + $this->dispatch('error', 'Invalid Cron / Human expression for Server Cleanup Frequency. Resetting to default 10 minutes.'); + $this->server->settings->server_cleanup_frequency = '*/10 * * * *'; + } + } } public function serverInstalled() @@ -118,7 +130,6 @@ class Form extends Component } if ($this->server->settings->isDirty('is_server_api_enabled') && $this->server->settings->is_server_api_enabled === true) { ray('Starting sentinel'); - } } else { ray('Sentinel is not enabled'); @@ -158,7 +169,7 @@ class Form extends Component $this->server->settings->save(); $this->dispatch('proxyStatusUpdated'); } else { - $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: '.$error); + $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.

Check this documentation for further help.

Error: ' . $error); return; } @@ -174,7 +185,7 @@ class Form extends Component public function submit() { - if (isCloud() && ! isDev()) { + if (isCloud() && !isDev()) { $this->validate(); $this->validate([ 'server.ip' => 'required', @@ -192,9 +203,13 @@ class Form extends Component } refresh_server_connection($this->server->privateKey); $this->server->settings->wildcard_domain = $this->wildcard_domain; - $this->server->settings->cleanup_after_percentage = $this->cleanup_after_percentage; + if ($this->server->settings->force_server_cleanup) { + $this->server->settings->server_cleanup_frequency = $this->server->settings->server_cleanup_frequency; + } else { + $this->server->settings->server_cleanup_threshold = $this->server->settings->server_cleanup_threshold; + } $this->server->settings->save(); $this->server->save(); $this->dispatch('success', 'Server updated.'); } -} \ No newline at end of file +}