mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-15 17:22:34 -04: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.
69 lines
3.1 KiB
PHP
69 lines
3.1 KiB
PHP
<?php
|
|
|
|
use App\Models\NotificationThrottle;
|
|
use App\Models\ScheduledDatabaseBackup;
|
|
use App\Models\Server;
|
|
use App\Models\Team;
|
|
use App\Notifications\Database\BackupMissing;
|
|
use App\Notifications\Server\Unreachable;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
Server::flushIdentityMap();
|
|
});
|
|
|
|
it('moves the old notification markers into notification_throttles and back', function () {
|
|
$team = Team::factory()->create();
|
|
$localhost = Server::factory()->create(['id' => 0, 'team_id' => $team->id]);
|
|
$notifiedServer = Server::factory()->create(['team_id' => $team->id]);
|
|
$quietServer = Server::factory()->create(['team_id' => $team->id]);
|
|
$notifiedBackup = ScheduledDatabaseBackup::create([
|
|
'enabled' => true,
|
|
'frequency' => '0 0 * * *',
|
|
'save_s3' => false,
|
|
'database_type' => 'App\\Models\\StandalonePostgresql',
|
|
'database_id' => 999,
|
|
'team_id' => $team->id,
|
|
]);
|
|
$quietBackup = $notifiedBackup->replicate(['uuid']);
|
|
$quietBackup->save();
|
|
|
|
$migration = require database_path('migrations/2026_09_29_083244_create_notification_throttles_table.php');
|
|
$migration->down();
|
|
|
|
DB::table('servers')->whereIn('id', [$localhost->id, $notifiedServer->id])->update(['unreachable_notification_sent' => true]);
|
|
DB::table('scheduled_database_backups')->where('id', $notifiedBackup->id)->update(['missing_backup_notification_sent_at' => '2026-09-01 10:00:00']);
|
|
|
|
$migration->up();
|
|
|
|
expect(Schema::hasColumn('servers', 'unreachable_notification_sent'))->toBeFalse()
|
|
->and(Schema::hasColumn('scheduled_database_backups', 'missing_backup_notification_sent_at'))->toBeFalse()
|
|
->and(NotificationThrottle::query()->count())->toBe(3)
|
|
->and(NotificationThrottle::wasSent($localhost, Unreachable::class))->toBeTrue()
|
|
->and(NotificationThrottle::wasSent($notifiedServer, Unreachable::class))->toBeTrue()
|
|
->and(NotificationThrottle::wasSent($quietServer, Unreachable::class))->toBeFalse()
|
|
->and(NotificationThrottle::wasSent($quietBackup, BackupMissing::class))->toBeFalse()
|
|
->and(NotificationThrottle::query()
|
|
->whereMorphedTo('notifiable', $notifiedBackup)
|
|
->where('notification', BackupMissing::class)
|
|
->sole()
|
|
->sent_at
|
|
->toDateTimeString())->toBe('2026-09-01 10:00:00');
|
|
|
|
$migration->down();
|
|
|
|
expect(Schema::hasTable('notification_throttles'))->toBeFalse()
|
|
->and(DB::table('servers')->where('unreachable_notification_sent', true)->pluck('id')->sort()->values()->all())
|
|
->toBe([$localhost->id, $notifiedServer->id])
|
|
->and(DB::table('scheduled_database_backups')->where('id', $notifiedBackup->id)->value('missing_backup_notification_sent_at'))
|
|
->toStartWith('2026-09-01 10:00:00')
|
|
->and(DB::table('scheduled_database_backups')->where('id', $quietBackup->id)->value('missing_backup_notification_sent_at'))
|
|
->toBeNull();
|
|
|
|
$migration->up();
|
|
});
|