166 lines
5.2 KiB
PHP
166 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Widgets;
|
|
|
|
use Filament\Widgets\Widget;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
class QueueHealthWidget extends Widget
|
|
{
|
|
protected string $view = 'filament.widgets.queue-health';
|
|
|
|
protected ?string $pollingInterval = '60s';
|
|
|
|
protected int|string|array $columnSpan = 'full';
|
|
|
|
protected function getViewData(): array
|
|
{
|
|
$snapshot = Cache::get('storage:queue-health:last');
|
|
$stalledMinutes = (int) config('storage-monitor.queue_health.stalled_minutes', 10);
|
|
|
|
if (! is_array($snapshot)) {
|
|
return [
|
|
'snapshotMissing' => true,
|
|
'connection' => (string) config('queue.default'),
|
|
'snapshotLabel' => __('admin.ops_health.snapshot_missing'),
|
|
'queues' => [],
|
|
'alerts' => [],
|
|
'alertCount' => 0,
|
|
'stalledAssets' => 0,
|
|
'stalledMinutes' => $stalledMinutes,
|
|
];
|
|
}
|
|
|
|
$queues = collect($snapshot['queues'] ?? [])
|
|
->map(fn (array $queue) => $this->formatQueue($queue))
|
|
->values()
|
|
->all();
|
|
|
|
$alerts = collect($snapshot['alerts'] ?? [])
|
|
->map(fn (array $alert) => $this->formatAlert($alert))
|
|
->values()
|
|
->all();
|
|
|
|
$snapshotAge = $this->formatSnapshotAge($snapshot['generated_at'] ?? null);
|
|
$snapshotLabel = $snapshotAge
|
|
? __('admin.ops_health.snapshot_age', ['age' => $snapshotAge])
|
|
: __('admin.ops_health.snapshot_missing');
|
|
|
|
return [
|
|
'snapshotMissing' => false,
|
|
'connection' => (string) ($snapshot['connection'] ?? config('queue.default')),
|
|
'snapshotLabel' => $snapshotLabel,
|
|
'queues' => $queues,
|
|
'alerts' => $alerts,
|
|
'alertCount' => count($alerts),
|
|
'stalledAssets' => (int) ($snapshot['stalled_assets'] ?? 0),
|
|
'stalledMinutes' => $stalledMinutes,
|
|
'statusSummary' => $this->summarizeSeverities($queues),
|
|
];
|
|
}
|
|
|
|
private function formatQueue(array $queue): array
|
|
{
|
|
$size = (int) ($queue['size'] ?? 0);
|
|
$failed = (int) ($queue['failed'] ?? 0);
|
|
$limits = $queue['limits'] ?? [];
|
|
|
|
return [
|
|
'name' => (string) ($queue['queue'] ?? 'default'),
|
|
'size' => $size,
|
|
'size_label' => $size < 0 ? '-' : number_format($size),
|
|
'failed' => $failed,
|
|
'failed_label' => number_format($failed),
|
|
'severity' => (string) ($queue['severity'] ?? 'unknown'),
|
|
'warning' => (int) ($limits['warning'] ?? 0),
|
|
'critical' => (int) ($limits['critical'] ?? 0),
|
|
'utilization_label' => $this->formatUtilizationLabel($size, $limits),
|
|
];
|
|
}
|
|
|
|
private function formatAlert(array $alert): array
|
|
{
|
|
return [
|
|
'queue' => $alert['queue'] ?? null,
|
|
'type' => (string) ($alert['type'] ?? 'unknown'),
|
|
'severity' => (string) ($alert['severity'] ?? 'warning'),
|
|
'size' => $alert['size'] ?? null,
|
|
'failed' => $alert['failed'] ?? null,
|
|
'count' => $alert['count'] ?? null,
|
|
'older_than_minutes' => $alert['older_than_minutes'] ?? null,
|
|
];
|
|
}
|
|
|
|
private function formatSnapshotAge(?string $timestamp): ?string
|
|
{
|
|
if (! $timestamp) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return Carbon::parse($timestamp)->diffForHumans();
|
|
} catch (\Throwable) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private function summarizeSeverities(array $queues): array
|
|
{
|
|
$counts = [
|
|
'ok' => 0,
|
|
'warning' => 0,
|
|
'critical' => 0,
|
|
'unknown' => 0,
|
|
];
|
|
|
|
foreach ($queues as $queue) {
|
|
$severity = $queue['severity'] ?? 'unknown';
|
|
if (! array_key_exists($severity, $counts)) {
|
|
$severity = 'unknown';
|
|
}
|
|
|
|
$counts[$severity]++;
|
|
}
|
|
|
|
return collect($counts)
|
|
->map(fn (int $count, string $severity) => [
|
|
'severity' => $severity,
|
|
'label' => __('admin.ops_health.severity.'.$severity),
|
|
'count' => $count,
|
|
])
|
|
->values()
|
|
->all();
|
|
}
|
|
|
|
private function formatUtilizationLabel(int $size, array $limits): string
|
|
{
|
|
if ($size < 0) {
|
|
return __('admin.ops_health.queue.utilization_na');
|
|
}
|
|
|
|
$critical = (int) ($limits['critical'] ?? 0);
|
|
$warning = (int) ($limits['warning'] ?? 0);
|
|
|
|
if ($critical > 0) {
|
|
$percent = (int) round(($size / $critical) * 100);
|
|
|
|
return __('admin.ops_health.queue.utilization_of', [
|
|
'percent' => $percent,
|
|
'label' => __('admin.ops_health.severity.critical'),
|
|
]);
|
|
}
|
|
|
|
if ($warning > 0) {
|
|
$percent = (int) round(($size / $warning) * 100);
|
|
|
|
return __('admin.ops_health.queue.utilization_of', [
|
|
'percent' => $percent,
|
|
'label' => __('admin.ops_health.severity.warning'),
|
|
]);
|
|
}
|
|
|
|
return __('admin.ops_health.queue.utilization_na');
|
|
}
|
|
}
|