diff --git a/.env.example b/.env.example index c9a868c..5fb97bc 100644 --- a/.env.example +++ b/.env.example @@ -63,3 +63,5 @@ AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false VITE_APP_NAME="${APP_NAME}" + +HEALTH_CHECK_INTERVAL=24 diff --git a/app/Console/Commands/PerformSiteHealthCheck.php b/app/Console/Commands/PerformSiteHealthCheck.php index f8c63ad..856a977 100644 --- a/app/Console/Commands/PerformSiteHealthCheck.php +++ b/app/Console/Commands/PerformSiteHealthCheck.php @@ -25,10 +25,13 @@ class PerformSiteHealthCheck extends Command /** * Execute the console command. */ - public function handle() + public function handle(): int { - CheckSiteHealth::dispatchSync( - Site::findOrFail($this->input->getArgument('siteId')) - ); + /** @var Site $site */ + $site = Site::findOrFail($this->input->getArgument('siteId')); + + CheckSiteHealth::dispatchSync($site); + + return Command::SUCCESS; } } diff --git a/app/Console/Commands/QueueHealthChecks.php b/app/Console/Commands/QueueHealthChecks.php new file mode 100644 index 0000000..06cd153 --- /dev/null +++ b/app/Console/Commands/QueueHealthChecks.php @@ -0,0 +1,61 @@ +output->writeln('Pushing pending health checks'); + + Site::query() + ->whereDate( + 'last_seen', + '<', + Carbon::now()->subHours((int) config('autoupdates.healthcheck_interval')) // @phpstan-ignore-line + ) + ->chunkById( + 100, + function (Collection $chunk) { + // Show progress + $this->output->write('.'); + + $this->totalPushed += $chunk->count(); + + // Push each site check to queue + $chunk->each(fn ($site) => CheckSiteHealth::dispatch($site)); + } + ); + + // Result + $this->output->writeln(""); + $this->output->writeln('Pushed ' . $this->totalPushed . ' pending jobs to queue'); + + return Command::SUCCESS; + } +} diff --git a/app/Jobs/CheckSiteHealth.php b/app/Jobs/CheckSiteHealth.php index 3e0ab36..6de3a2c 100644 --- a/app/Jobs/CheckSiteHealth.php +++ b/app/Jobs/CheckSiteHealth.php @@ -6,6 +6,7 @@ use App\Models\Site; use App\Services\SiteConnectionService; +use Carbon\Carbon; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; @@ -33,7 +34,7 @@ public function handle(): void $healthData = collect($response); // Write updated data to DB - $this->site->update( + $this->site->fill( $healthData->only([ 'php_version', 'db_type', @@ -42,5 +43,9 @@ public function handle(): void 'server_os' ])->toArray() ); + + // @phpstan-ignore-next-line + $this->site->last_seen = Carbon::now(); + $this->site->save(); } } diff --git a/app/Services/SiteConnectionService.php b/app/Services/SiteConnectionService.php index af19cb5..a855e9c 100644 --- a/app/Services/SiteConnectionService.php +++ b/app/Services/SiteConnectionService.php @@ -95,12 +95,23 @@ protected function performHttpRequest( ); } - // Return decoded body - return json_decode( + // Decode body + $return = json_decode( (string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR ); + + // Make sure it's an array + if (!is_array($return)) { + throw new RequestException( + "Invalid JSON body", + $request, + $response + ); + } + + return $return; } } diff --git a/config/app.php b/config/app.php index 7200021..c10c9c9 100644 --- a/config/app.php +++ b/config/app.php @@ -121,6 +121,5 @@ 'maintenance' => [ 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), 'store' => env('APP_MAINTENANCE_STORE', 'database'), - ], - + ] ]; diff --git a/config/autoupdates.php b/config/autoupdates.php new file mode 100644 index 0000000..8ca0839 --- /dev/null +++ b/config/autoupdates.php @@ -0,0 +1,5 @@ + env('HEALTH_CHECK_INTERVAL', 24) +]; diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 23cd8c3..cde55cc 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,5 +7,8 @@ parameters: paths: - app/ - # Level 9 is the highest level - level: 5 + level: 9 + + ignoreErrors: + - '#Method .* return type has no value type specified in iterable type array.#' + - '#Method .* has parameter .* with no value type specified in iterable type array.#' diff --git a/routes/console.php b/routes/console.php index ec6db2f..b05cd0e 100644 --- a/routes/console.php +++ b/routes/console.php @@ -2,5 +2,7 @@ use Illuminate\Support\Facades\Schedule; use Illuminate\Queue\Console\PruneFailedJobsCommand; +use App\Console\Commands\QueueHealthChecks; Schedule::command(PruneFailedJobsCommand::class)->daily(); +Schedule::command(QueueHealthChecks::class)->everyFifteenMinutes();