argument('source'); try { $definition = $sources->definition($source); } catch (InvalidArgumentException $exception) { $this->components->error($exception->getMessage()); return self::FAILURE; } if (! $sources->enabled($source)) { $this->components->info($definition['label'] . '同步未启用,本轮跳过。'); return self::SUCCESS; } try { $cache = $caches->forSource($source); $refresher = $refreshers->forSource($source); } catch (InvalidArgumentException $exception) { $this->components->error($exception->getMessage()); return self::FAILURE; } $configuredLimit = max((int) $cache->setting('snapshots.refresh_limit', 2), 1); $requestedLimit = (int) ($this->option('limit') ?: $configuredLimit); $entries = $cache->activeEntries(min(max($requestedLimit, 1), $configuredLimit)); $timeBudget = max((int) $cache->setting('snapshots.refresh_time_budget_seconds', 45), 10); $startedAt = microtime(true); if ($entries === []) { $this->components->info('没有需要刷新的活跃查询。'); return self::SUCCESS; } $fresh = 0; $stale = 0; $failed = 0; foreach ($entries as $entry) { if ((microtime(true) - $startedAt) >= $timeBudget) { $this->components->info('本轮刷新已达到时间预算,剩余查询留到下一轮。'); break; } try { $status = $refresher->refresh($entry); $status === 'fresh' ? $fresh++ : $stale++; } catch (Throwable $exception) { // 单个查询失败只重置当前来源连接并跳过该查询,不能让它 // 每分钟阻断同一来源的其他页面。 UpstreamOdbcConnection::reset($source); $failed++; Log::error('上游活跃快照刷新失败,本轮已跳过该查询。', [ 'source' => $definition['key'], 'source_label' => $definition['label'], 'scope' => $entry['scope'] ?? 'unknown', 'exception' => $exception::class, ]); $this->components->warn('一个上游查询刷新失败,已跳过并继续;错误类型:' . $exception::class); } $pauseMs = max((int) $cache->setting('snapshots.refresh_pause_ms', 300), 0); if ($pauseMs > 0) { usleep($pauseMs * 1000); } } $this->components->info("快照刷新完成:新鲜 {$fresh},沿用旧快照 {$stale},失败 {$failed}。"); return $failed > 0 ? self::FAILURE : self::SUCCESS; } }