Ship production optimization M1-M12.5A: queues, metrics, HTTP observability, and vector search reliability.
Keep similar-ai from tripping the global circuit on a lone URL 502, clamp Qdrant search to 100, and add Server-Timing plus slow-request logging. Studio shared props, Academy S3 exists caching, heat chunking, and Redis/scheduler hygiene stay in this rollout.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Services\Traffic\OnlineVisitorRepository;
|
||||
use App\Services\Traffic\PresenceIndexPruner;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class PruneOnlineVisitorIndexCommand extends Command
|
||||
{
|
||||
protected $signature = 'skinbase:prune-online-visitor-index
|
||||
{--dry-run : Count stale members without SREM}
|
||||
{--execute : Remove stale members}
|
||||
{--scan-count= : SSCAN COUNT}
|
||||
{--max-batches= : Batches this run}
|
||||
{--max-members= : Members to inspect this run}
|
||||
{--sleep-ms= : Pause between batches}
|
||||
{--time-limit= : Stop after N seconds (0 = none)}';
|
||||
|
||||
protected $description = 'Remove stale members from the online-visitor Redis set (SSCAN, never SMEMBERS)';
|
||||
|
||||
public function handle(PresenceIndexPruner $pruner): int
|
||||
{
|
||||
$dryRun = (bool) $this->option('dry-run');
|
||||
$execute = (bool) $this->option('execute');
|
||||
if ($dryRun === $execute) {
|
||||
$this->error('Pass exactly one of --dry-run or --execute.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$scanCount = $this->intOption('scan-count', (int) config('traffic.online_visitors.prune_scan_count', 500));
|
||||
$maxBatches = $this->intOption('max-batches', (int) config('traffic.online_visitors.prune_max_batches', 200));
|
||||
$maxMembers = $this->intOption('max-members', (int) config('traffic.online_visitors.prune_max_members', 100000));
|
||||
$sleepMs = $this->intOption('sleep-ms', (int) config('traffic.online_visitors.prune_sleep_ms', 25));
|
||||
$timeLimit = $this->intOption('time-limit', 0);
|
||||
|
||||
$scard = (int) Redis::scard(OnlineVisitorRepository::INDEX_KEY);
|
||||
|
||||
$this->info(sprintf(
|
||||
'[prune-online-visitor-index] key=%s prefix=%s scard=%d scan_count=%d max_batches=%d max_members=%d sleep_ms=%d %s',
|
||||
OnlineVisitorRepository::INDEX_KEY,
|
||||
(string) config('database.redis.options.prefix'),
|
||||
$scard,
|
||||
$scanCount,
|
||||
$maxBatches,
|
||||
$maxMembers,
|
||||
$sleepMs,
|
||||
$dryRun ? 'dry-run' : 'execute'
|
||||
));
|
||||
|
||||
$result = $pruner->prune(
|
||||
$scanCount,
|
||||
$maxBatches,
|
||||
$maxMembers,
|
||||
$sleepMs,
|
||||
$dryRun,
|
||||
$timeLimit > 0 ? $timeLimit : null,
|
||||
);
|
||||
|
||||
$this->info(sprintf(
|
||||
'scanned=%d stale=%d live=%d removed=%d batches=%d',
|
||||
$result['scanned'],
|
||||
$result['stale'],
|
||||
$result['live'],
|
||||
$result['removed'],
|
||||
$result['batches']
|
||||
));
|
||||
|
||||
Log::info('[prune-online-visitor-index] completed', $result + ['scard_before' => $scard]);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function intOption(string $name, int $default): int
|
||||
{
|
||||
$raw = $this->option($name);
|
||||
if ($raw === null || $raw === '') {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return max(0, (int) $raw);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user