mirror of
https://github.com/coollabsio/coolify.git
synced 2026-10-29 01:54:37 +08:00
High disk usage notifications were sent every ~10 minutes on Coolify Cloud because the cache rate limiter did not hold across Sentinel-triggered checks. - Add a notification_throttles table and NotificationThrottle helper that atomically records when a notification was sent for a resource. - Add the ThrottledNotification contract; Team::notify() skips a throttled notification that was already sent within its interval. - High disk usage: configurable per-server interval (server_disk_usage_notification_interval_hours, default 24h) in Server > Advanced and the servers API. - Container restarted (coolify-proxy, database TCP proxy): at most one notification per hour per server/database during a restart loop. - Move the unreachable and missing-backup markers into the new table and migrate existing data (servers.unreachable_notification_sent and scheduled_database_backups.missing_backup_notification_sent_at). - Regenerate OpenAPI files.
103 lines
3.4 KiB
PHP
103 lines
3.4 KiB
PHP
<?php
|
|
|
|
use App\Events\ServerReachabilityChanged;
|
|
use App\Models\NotificationThrottle;
|
|
use App\Models\Server;
|
|
use App\Models\Team;
|
|
use App\Notifications\Channels\EmailChannel;
|
|
use App\Notifications\Server\Reachable;
|
|
use App\Notifications\Server\Unreachable;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Notification;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
$this->team = Team::factory()->create();
|
|
$this->team->emailNotificationSettings()->update([
|
|
'use_instance_email_settings' => true,
|
|
'server_unreachable_email_notifications' => true,
|
|
'server_reachable_email_notifications' => true,
|
|
]);
|
|
|
|
$this->server = Server::factory()->create(['team_id' => $this->team->id]);
|
|
|
|
Notification::fake();
|
|
});
|
|
|
|
it('sends Unreachable notification when threshold reached and not yet notified', function () {
|
|
$this->server->settings()->update(['is_reachable' => false]);
|
|
$this->server->forceFill([
|
|
'unreachable_count' => 2,
|
|
])->save();
|
|
|
|
ServerReachabilityChanged::dispatch($this->server->fresh());
|
|
|
|
Notification::assertSentTo($this->team, Unreachable::class);
|
|
expect($this->server->fresh()->unreachable_notification_sent)->toBeTrue();
|
|
});
|
|
|
|
it('does not send Unreachable on first transient failure (count=1)', function () {
|
|
$this->server->settings()->update(['is_reachable' => false]);
|
|
$this->server->forceFill([
|
|
'unreachable_count' => 1,
|
|
])->save();
|
|
|
|
ServerReachabilityChanged::dispatch($this->server->fresh());
|
|
|
|
Notification::assertNothingSent();
|
|
});
|
|
|
|
it('does not send Unreachable when already notified', function () {
|
|
$this->server->settings()->update(['is_reachable' => false]);
|
|
$this->server->forceFill([
|
|
'unreachable_count' => 5,
|
|
])->save();
|
|
NotificationThrottle::record($this->server, Unreachable::class);
|
|
|
|
ServerReachabilityChanged::dispatch($this->server->fresh());
|
|
|
|
Notification::assertNothingSent();
|
|
});
|
|
|
|
it('sends Reachable notification on recovery when previously notified', function () {
|
|
$this->server->settings()->update(['is_reachable' => true]);
|
|
$this->server->forceFill([
|
|
'unreachable_count' => 0,
|
|
])->save();
|
|
NotificationThrottle::record($this->server, Unreachable::class);
|
|
|
|
$fresh = $this->server->fresh();
|
|
expect($fresh->unreachable_notification_sent)->toBeTrue();
|
|
expect((bool) $fresh->settings->is_reachable)->toBeTrue();
|
|
|
|
ServerReachabilityChanged::dispatch($fresh);
|
|
|
|
Notification::assertSentTo($this->team, Reachable::class);
|
|
expect($this->server->fresh()->unreachable_notification_sent)->toBeFalse();
|
|
});
|
|
|
|
it('does not send Reachable when never notified', function () {
|
|
$this->server->settings()->update(['is_reachable' => true]);
|
|
$this->server->forceFill([
|
|
'unreachable_count' => 0,
|
|
])->save();
|
|
|
|
ServerReachabilityChanged::dispatch($this->server->fresh());
|
|
|
|
Notification::assertNothingSent();
|
|
});
|
|
|
|
it('routes Unreachable notification through EmailChannel when email toggle is on', function () {
|
|
$this->server->settings()->update(['is_reachable' => false]);
|
|
$this->server->forceFill([
|
|
'unreachable_count' => 2,
|
|
])->save();
|
|
|
|
ServerReachabilityChanged::dispatch($this->server->fresh());
|
|
|
|
Notification::assertSentTo($this->team, Unreachable::class, function ($notification, $channels) {
|
|
return in_array(EmailChannel::class, $channels);
|
|
});
|
|
});
|