<?php
 namespace App\Services\Domain; use App\Models\ClientDomain; use App\Models\Setting; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Log; class DomainSyncScheduler { public function dueCommands(): array { $due = []; $fullCycle = (int) Setting::getValue('domain_sync_cycle_days', 7); $batchLimit = (int) Setting::getValue('domain_sync_batch_limit', 100); if ($this->isBatchDue('full', $fullCycle, $batchLimit)) { $due[] = [ 'type' => 'full', 'command' => "domains:sync --all --queue --limit={$batchLimit}", 'reason' => "Full-list cycle {$fullCycle}d, batch due", ]; } $expCycle = (int) Setting::getValue('domain_expiring_sync_cycle_days', 1); if ($this->isBatchDue('expiring', $expCycle, $batchLimit)) { $days = (int) Setting::getValue('domain_expiring_sync_days', 30); $due[] = [ 'type' => 'expiring', 'command' => "domains:sync --expiring --days={$days} --queue", 'reason' => "Expiring cycle {$expCycle}d, batch due (threshold {$days}d)", ]; } $tCycle = (int) Setting::getValue('domain_transfer_sync_cycle_days', 1); if ($this->isBatchDue('transfer', $tCycle, $batchLimit, scope: 'pending_transfer')) { $due[] = [ 'type' => 'transfer', 'command' => 'domains:sync-transfers', 'reason' => "Transfer cycle {$tCycle}d, batch due", ]; } return $due; } public function tick(): array { $fired = []; foreach ($this->dueCommands() as $batch) { Artisan::call($batch['command']); $this->markBatchFired($batch['type']); Log::info('DomainSyncScheduler fired batch', $batch); $fired[] = $batch; } return $fired; } protected function isBatchDue(string $type, int $cycleDays, int $batchLimit, string $scope = 'active'): bool { $totalDomains = $scope === 'pending_transfer' ? ClientDomain::where('status', 'pending_transfer')->count() : ClientDomain::where('status', 'active')->count(); if ($totalDomains === 0) { return false; } $batchCount = max(1, (int) ceil($totalDomains / max(1, $batchLimit))); $cycleMinutes = $cycleDays * 24 * 60; $interBatchMinutes = max(5, (int) floor($cycleMinutes / $batchCount)); $lastBatchKey = "domain_sync_last_batch_{$type}_at"; $lastBatchAt = Setting::getValue($lastBatchKey); if (! $lastBatchAt) { return true; } $elapsed = Carbon::parse($lastBatchAt)->diffInMinutes(now()); return $elapsed >= $interBatchMinutes; } protected function markBatchFired(string $type): void { Setting::set("domain_sync_last_batch_{$type}_at", now()->toDateTimeString()); } } 