option('from')); $toRaw = trim((string) $this->option('to')); try { $start = $this->parsePeopleCountingDay($fromRaw !== '' ? $fromRaw : '2026-08-03'); $end = $toRaw !== '' ? $this->parsePeopleCountingDay($toRaw) : Carbon::yesterday()->startOfDay(); if ($start->gt($end)) { throw new InvalidArgumentException('--from 不能晚于 --to'); } } catch (InvalidArgumentException $e) { $this->error($e->getMessage()); return self::FAILURE; } $doDaily = ! (bool) $this->option('skip-daily'); $doHourly = ! (bool) $this->option('skip-hourly'); $skipIfAllZero = ! (bool) $this->option('include-empty'); $sleepMs = $this->peopleCountingSleepMs(); $today = Carbon::today()->toDateString(); $fail = 0; $this->info(sprintf( 'backfill %s ~ %s daily=%s hourly=%s', $start->toDateString(), $end->toDateString(), $doDaily ? 'yes' : 'no', $doHourly ? 'yes' : 'no' )); for ($day = $start->copy(); $day->lte($end); $day->addDay()) { $d = $day->toDateString(); if ($d > $today) { $this->warn("跳过未来日期 {$d}"); continue; } if ($doDaily) { try { $r = $sync->syncDailyForDate($day, true); $this->line(sprintf(' daily %s written=%d skipped=%d', $r['date'], $r['written'], $r['skipped'])); Log::info('people-counting.backfill.daily', $r); } catch (Throwable $e) { $fail++; $this->error(" daily {$d} 失败: ".$e->getMessage()); Log::warning('people-counting.backfill.daily.failed', [ 'date' => $d, 'error' => $e->getMessage(), ]); } } if ($doHourly) { try { $r = $sync->syncHourlyForDate($day, $skipIfAllZero); $this->line($r['skipped'] ? sprintf(' hourly %s skipped empty memory dataSource=%s', $r['date'], $r['data_source'] ?? 'null') : sprintf(' hourly %s written=%d dataSource=%s', $r['date'], $r['written'], $r['data_source'] ?? 'null')); Log::info('people-counting.backfill.hourly', $r); } catch (Throwable $e) { $fail++; $this->error(" hourly {$d} 失败: ".$e->getMessage()); Log::warning('people-counting.backfill.hourly.failed', [ 'date' => $d, 'error' => $e->getMessage(), ]); } } if ($day->copy()->addDay()->lte($end) && $sleepMs > 0) { usleep($sleepMs * 1000); } } return $fail > 0 ? self::FAILURE : self::SUCCESS; } }