chore(sentinel): remove stale resource exit check
This commit is contained in:
parent
626cfb4a22
commit
90aa4e7e73
3 changed files with 0 additions and 179 deletions
|
|
@ -1,97 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Actions\Server;
|
|
||||||
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\ServiceApplication;
|
|
||||||
use App\Models\ServiceDatabase;
|
|
||||||
use App\Models\StandaloneClickhouse;
|
|
||||||
use App\Models\StandaloneDocker;
|
|
||||||
use App\Models\StandaloneDragonfly;
|
|
||||||
use App\Models\StandaloneKeydb;
|
|
||||||
use App\Models\StandaloneMariadb;
|
|
||||||
use App\Models\StandaloneMongodb;
|
|
||||||
use App\Models\StandaloneMysql;
|
|
||||||
use App\Models\StandalonePostgresql;
|
|
||||||
use App\Models\StandaloneRedis;
|
|
||||||
use App\Models\SwarmDocker;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
|
||||||
|
|
||||||
class ResourcesCheck
|
|
||||||
{
|
|
||||||
use AsAction;
|
|
||||||
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$seconds = config('constants.sentinel.resource_stale_seconds', 300);
|
|
||||||
$staleServerIds = $this->staleSentinelServerIds($seconds);
|
|
||||||
|
|
||||||
if ($staleServerIds->isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[$standaloneDockerIds, $swarmDockerIds] = $this->destinationIdsForServers($staleServerIds);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Application::where(fn ($query) => $this->scopeDestination($query, $standaloneDockerIds, $swarmDockerIds))
|
|
||||||
->where('status', 'not like', 'exited%')
|
|
||||||
->update(['status' => 'exited']);
|
|
||||||
|
|
||||||
ServiceApplication::whereHas('service', fn ($query) => $query->whereIn('server_id', $staleServerIds))
|
|
||||||
->where('status', 'not like', 'exited%')
|
|
||||||
->update(['status' => 'exited']);
|
|
||||||
|
|
||||||
ServiceDatabase::whereHas('service', fn ($query) => $query->whereIn('server_id', $staleServerIds))
|
|
||||||
->where('status', 'not like', 'exited%')
|
|
||||||
->update(['status' => 'exited']);
|
|
||||||
|
|
||||||
collect([
|
|
||||||
StandalonePostgresql::class,
|
|
||||||
StandaloneRedis::class,
|
|
||||||
StandaloneMongodb::class,
|
|
||||||
StandaloneMysql::class,
|
|
||||||
StandaloneMariadb::class,
|
|
||||||
StandaloneKeydb::class,
|
|
||||||
StandaloneDragonfly::class,
|
|
||||||
StandaloneClickhouse::class,
|
|
||||||
])->each(function (string $databaseClass) use ($standaloneDockerIds, $swarmDockerIds) {
|
|
||||||
$databaseClass::query()
|
|
||||||
->where(fn ($query) => $this->scopeDestination($query, $standaloneDockerIds, $swarmDockerIds))
|
|
||||||
->where('status', 'not like', 'exited%')
|
|
||||||
->update(['status' => 'exited']);
|
|
||||||
});
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function staleSentinelServerIds(int $seconds): Collection
|
|
||||||
{
|
|
||||||
return Server::query()
|
|
||||||
->whereNotNull('sentinel_updated_at')
|
|
||||||
->where('sentinel_updated_at', '<', now()->subSeconds($seconds))
|
|
||||||
->whereHas('settings', fn ($query) => $query->where('is_sentinel_enabled', true))
|
|
||||||
->pluck('id');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function destinationIdsForServers(Collection $serverIds): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
StandaloneDocker::whereIn('server_id', $serverIds)->pluck('id'),
|
|
||||||
SwarmDocker::whereIn('server_id', $serverIds)->pluck('id'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function scopeDestination($query, Collection $standaloneDockerIds, Collection $swarmDockerIds): void
|
|
||||||
{
|
|
||||||
$query->where(function ($query) use ($standaloneDockerIds) {
|
|
||||||
$query->where('destination_type', StandaloneDocker::class)
|
|
||||||
->whereIn('destination_id', $standaloneDockerIds);
|
|
||||||
})->orWhere(function ($query) use ($swarmDockerIds) {
|
|
||||||
$query->where('destination_type', SwarmDocker::class)
|
|
||||||
->whereIn('destination_id', $swarmDockerIds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -98,10 +98,6 @@
|
||||||
// every push.
|
// every push.
|
||||||
'push_force_interval_seconds' => env('SENTINEL_PUSH_FORCE_INTERVAL_SECONDS', 300),
|
'push_force_interval_seconds' => env('SENTINEL_PUSH_FORCE_INTERVAL_SECONDS', 300),
|
||||||
|
|
||||||
// How long a Sentinel-enabled server may go without a heartbeat before
|
|
||||||
// ResourcesCheck considers its resources stale. Per-resource
|
|
||||||
// last_online_at is only updated on real status changes, not every push.
|
|
||||||
'resource_stale_seconds' => env('SENTINEL_RESOURCE_STALE_SECONDS', 300),
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'proxy' => [
|
'proxy' => [
|
||||||
|
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use App\Actions\Server\ResourcesCheck;
|
|
||||||
use App\Models\Application;
|
|
||||||
use App\Models\Environment;
|
|
||||||
use App\Models\Project;
|
|
||||||
use App\Models\Server;
|
|
||||||
use App\Models\StandaloneDocker;
|
|
||||||
use App\Models\Team;
|
|
||||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
|
|
||||||
uses(RefreshDatabase::class);
|
|
||||||
|
|
||||||
it('does not mark resources exited when sentinel is still reporting for the server', function () {
|
|
||||||
Carbon::setTestNow(Carbon::create(2026, 5, 27, 12, 0, 0, 'UTC'));
|
|
||||||
config(['constants.sentinel.resource_stale_seconds' => 300]);
|
|
||||||
|
|
||||||
$application = resourcesCheckApplication([
|
|
||||||
'last_online_at' => now()->subHour(),
|
|
||||||
'status' => 'running:healthy',
|
|
||||||
], [
|
|
||||||
'sentinel_updated_at' => now()->subMinute(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
ResourcesCheck::run();
|
|
||||||
|
|
||||||
$application->refresh();
|
|
||||||
|
|
||||||
expect($application->status)->toBe('running:healthy');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('marks resources exited when their sentinel server is stale', function () {
|
|
||||||
Carbon::setTestNow(Carbon::create(2026, 5, 27, 12, 0, 0, 'UTC'));
|
|
||||||
config(['constants.sentinel.resource_stale_seconds' => 300]);
|
|
||||||
|
|
||||||
$application = resourcesCheckApplication([
|
|
||||||
'last_online_at' => now()->subHour(),
|
|
||||||
'status' => 'running:healthy',
|
|
||||||
], [
|
|
||||||
'sentinel_updated_at' => now()->subMinutes(10),
|
|
||||||
]);
|
|
||||||
|
|
||||||
ResourcesCheck::run();
|
|
||||||
|
|
||||||
$application->refresh();
|
|
||||||
|
|
||||||
expect($application->status)->toBe('exited:unhealthy');
|
|
||||||
});
|
|
||||||
|
|
||||||
function resourcesCheckApplication(array $applicationAttributes = [], array $serverAttributes = []): Application
|
|
||||||
{
|
|
||||||
$lastOnlineAt = $applicationAttributes['last_online_at'] ?? null;
|
|
||||||
unset($applicationAttributes['last_online_at']);
|
|
||||||
|
|
||||||
$team = Team::factory()->create();
|
|
||||||
$server = Server::factory()->create(array_merge([
|
|
||||||
'team_id' => $team->id,
|
|
||||||
], $serverAttributes));
|
|
||||||
$server->settings()->update(['is_sentinel_enabled' => true]);
|
|
||||||
|
|
||||||
$destination = StandaloneDocker::where('server_id', $server->id)->first()
|
|
||||||
?? StandaloneDocker::factory()->create(['server_id' => $server->id]);
|
|
||||||
$project = Project::factory()->create(['team_id' => $team->id]);
|
|
||||||
$environment = Environment::factory()->create(['project_id' => $project->id]);
|
|
||||||
|
|
||||||
$application = Application::factory()->create(array_merge([
|
|
||||||
'environment_id' => $environment->id,
|
|
||||||
'destination_id' => $destination->id,
|
|
||||||
'destination_type' => $destination->getMorphClass(),
|
|
||||||
], $applicationAttributes));
|
|
||||||
|
|
||||||
if ($lastOnlineAt !== null) {
|
|
||||||
$application->forceFill(['last_online_at' => $lastOnlineAt])->saveQuietly();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $application;
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue