123 lines
3.9 KiB
PHP
123 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire;
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Redis;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Component;
|
|
|
|
#[Layout('layouts.app')]
|
|
class Dashboard extends Component
|
|
{
|
|
/** @var array<int, array{key:string,label:string,icon:string,state:string,detail:string}> */
|
|
public array $services = [];
|
|
|
|
public ?string $checkedAt = null;
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->refreshHealth();
|
|
}
|
|
|
|
/** Re-run all service health probes (called on mount, wire:poll and the refresh button). */
|
|
public function refreshHealth(): void
|
|
{
|
|
$this->services = [
|
|
$this->checkDatabase(),
|
|
$this->checkRedis(),
|
|
$this->checkReverb(),
|
|
$this->checkHorizon(),
|
|
];
|
|
|
|
$this->checkedAt = now()->format('H:i:s');
|
|
}
|
|
|
|
/** Worst state across services (drives the banner): offline > warning > online. */
|
|
public function worstState(): string
|
|
{
|
|
$states = array_column($this->services, 'state');
|
|
|
|
return in_array('offline', $states, true) ? 'offline'
|
|
: (in_array('warning', $states, true) ? 'warning' : 'online');
|
|
}
|
|
|
|
public function problemCount(): int
|
|
{
|
|
return count(array_filter($this->services, fn ($s) => $s['state'] !== 'online'));
|
|
}
|
|
|
|
protected function checkDatabase(): array
|
|
{
|
|
$base = ['key' => 'database', 'label' => __('dashboard.svc_database'), 'icon' => 'network'];
|
|
|
|
try {
|
|
$start = microtime(true);
|
|
DB::connection()->select('select 1');
|
|
$ms = (int) round((microtime(true) - $start) * 1000);
|
|
|
|
return $base + ['state' => 'online', 'detail' => $ms.' ms'];
|
|
} catch (\Throwable) {
|
|
return $base + ['state' => 'offline', 'detail' => __('dashboard.svc_unreachable')];
|
|
}
|
|
}
|
|
|
|
protected function checkRedis(): array
|
|
{
|
|
$base = ['key' => 'cache', 'label' => __('dashboard.svc_cache'), 'icon' => 'devices'];
|
|
|
|
try {
|
|
$start = microtime(true);
|
|
Redis::connection()->ping();
|
|
$ms = (int) round((microtime(true) - $start) * 1000);
|
|
|
|
return $base + ['state' => 'online', 'detail' => $ms.' ms'];
|
|
} catch (\Throwable) {
|
|
return $base + ['state' => 'offline', 'detail' => __('dashboard.svc_unreachable')];
|
|
}
|
|
}
|
|
|
|
protected function checkReverb(): array
|
|
{
|
|
$base = ['key' => 'realtime', 'label' => __('dashboard.svc_realtime'), 'icon' => 'activity'];
|
|
|
|
$host = config('broadcasting.connections.reverb.options.host', 'reverb');
|
|
$port = (int) config('broadcasting.connections.reverb.options.port', 8080);
|
|
|
|
$conn = @fsockopen($host, $port, $errno, $errstr, 1.0);
|
|
if ($conn) {
|
|
fclose($conn);
|
|
|
|
return $base + ['state' => 'online', 'detail' => $host.':'.$port];
|
|
}
|
|
|
|
return $base + ['state' => 'offline', 'detail' => __('dashboard.svc_unreachable')];
|
|
}
|
|
|
|
protected function checkHorizon(): array
|
|
{
|
|
$base = ['key' => 'queue', 'label' => __('dashboard.svc_queue'), 'icon' => 'automation'];
|
|
|
|
try {
|
|
$masters = app(\Laravel\Horizon\Contracts\MasterSupervisorRepository::class)->all();
|
|
|
|
if (empty($masters)) {
|
|
return $base + ['state' => 'offline', 'detail' => __('dashboard.svc_stopped')];
|
|
}
|
|
|
|
$running = collect($masters)->contains(fn ($m) => ($m->status ?? null) === 'running');
|
|
|
|
return $base + ($running
|
|
? ['state' => 'online', 'detail' => __('dashboard.svc_running')]
|
|
: ['state' => 'warning', 'detail' => __('dashboard.svc_stopped')]);
|
|
} catch (\Throwable) {
|
|
return $base + ['state' => 'offline', 'detail' => __('dashboard.svc_unreachable')];
|
|
}
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.dashboard');
|
|
}
|
|
}
|