From 2db26e88abd670b41848cde663f8130fd0d62743 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 15 Oct 2026 15:20:57 +0200 Subject: [PATCH] fix(jobs): stop notifying on transient CDN failures in version checks CheckHelperImageJob now logs a warning and returns when the versions endpoint fails instead of sending an internal notification and rethrowing. The next scheduled run retries. PullTemplatesFromCDN also no longer sends internal notifications on non-success responses or exceptions; it still logs them. Add tests checking that the stored helper version is kept and that no notification is sent when the CDN is unavailable. --- app/Jobs/CheckHelperImageJob.php | 27 +++++++++---------- app/Jobs/PullTemplatesFromCDN.php | 2 -- tests/Feature/HelperVersionTest.php | 17 ++++++++++++ .../PullServiceTemplatesFromCdnTest.php | 10 ++++++- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/app/Jobs/CheckHelperImageJob.php b/app/Jobs/CheckHelperImageJob.php index 6d76da8eb7..56118a238a 100644 --- a/app/Jobs/CheckHelperImageJob.php +++ b/app/Jobs/CheckHelperImageJob.php @@ -9,6 +9,7 @@ use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Log; class CheckHelperImageJob implements ShouldBeEncrypted, ShouldQueue { @@ -20,20 +21,18 @@ class CheckHelperImageJob implements ShouldBeEncrypted, ShouldQueue public function handle(): void { - try { - $response = Http::retry(3, 1000)->get(config('constants.coolify.versions_url')); - if ($response->successful()) { - $versions = $response->json(); - $settings = instanceSettings(); - $latest_version = data_get($versions, 'coolify.helper.version'); - $current_version = $settings->helper_version; - if (version_compare($latest_version, $current_version, '>')) { - $settings->update(['helper_version' => $latest_version]); - } - } - } catch (\Throwable $e) { - send_internal_notification('CheckHelperImageJob failed with: '.$e->getMessage()); - throw $e; + $response = Http::retry(3, 1000, throw: false)->get(config('constants.coolify.versions_url')); + if ($response->failed()) { + // The CDN can be briefly unavailable. The next scheduled run tries again, so do not notify. + Log::warning('CheckHelperImageJob could not fetch versions', ['status' => $response->status()]); + + return; + } + + $latest_version = data_get($response->json(), 'coolify.helper.version'); + $settings = instanceSettings(); + if (version_compare($latest_version, $settings->helper_version, '>')) { + $settings->update(['helper_version' => $latest_version]); } } } diff --git a/app/Jobs/PullTemplatesFromCDN.php b/app/Jobs/PullTemplatesFromCDN.php index ec09285e1e..2125581f50 100644 --- a/app/Jobs/PullTemplatesFromCDN.php +++ b/app/Jobs/PullTemplatesFromCDN.php @@ -44,13 +44,11 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue 'status' => $response->status(), 'body' => str($response->body())->limit(500)->toString(), ]); - send_internal_notification('PullTemplatesAndVersions failed with: '.$response->status().' '.$response->body()); } } catch (\Throwable $e) { Log::error('PullTemplatesFromCDN exception', [ 'message' => $e->getMessage(), ]); - send_internal_notification('PullTemplatesAndVersions failed with: '.$e->getMessage()); } } } diff --git a/tests/Feature/HelperVersionTest.php b/tests/Feature/HelperVersionTest.php index 64ef8466a7..6c203887fb 100644 --- a/tests/Feature/HelperVersionTest.php +++ b/tests/Feature/HelperVersionTest.php @@ -2,8 +2,10 @@ use App\Jobs\CheckHelperImageJob; use App\Models\InstanceSettings; +use App\Models\Team; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Http; +use Illuminate\Support\Facades\Notification; uses(RefreshDatabase::class); @@ -36,3 +38,18 @@ it('does not use a stored helper version older than the bundled version', functi expect(getHelperVersion())->toBe('1.0.17'); }); + +it('keeps the stored helper version and does not notify when the CDN is unavailable', function () { + Team::factory()->create(['id' => 0])->discordNotificationSettings()->update(['discord_enabled' => true]); + InstanceSettings::findOrFail(0)->update(['helper_version' => '1.0.17']); + Notification::fake(); + Http::preventStrayRequests(); + Http::fake([ + 'https://cdn.example.com/coolify/versions.json' => Http::response('error code: 1200', 503), + ]); + + (new CheckHelperImageJob)->handle(); + + expect(InstanceSettings::findOrFail(0)->helper_version)->toBe('1.0.17'); + Notification::assertNothingSent(); +}); diff --git a/tests/Feature/PullServiceTemplatesFromCdnTest.php b/tests/Feature/PullServiceTemplatesFromCdnTest.php index d70d787a76..1406721f27 100644 --- a/tests/Feature/PullServiceTemplatesFromCdnTest.php +++ b/tests/Feature/PullServiceTemplatesFromCdnTest.php @@ -1,10 +1,15 @@ '[1, 2]', ]); -it('logs when the CDN responds with a non-success status', function () { +it('logs without notifying when the CDN responds with a non-success status', function () { + Team::factory()->create(['id' => 0])->discordNotificationSettings()->update(['discord_enabled' => true]); + Notification::fake(); Http::fake([ 'cdn.coollabs.io/*' => Http::response('nope', 503), ]); @@ -160,4 +167,5 @@ it('logs when the CDN responds with a non-success status', function () { (new PullTemplatesFromCDN)->handle(); expect(Cache::get(service_templates_cache_key()))->toBeNull(); + Notification::assertNothingSent(); });