diff --git a/modules/EcommerceFinance/Services/UpstreamQueryCache.php b/modules/EcommerceFinance/Services/UpstreamQueryCache.php index abf620bd..e3d696f1 100644 --- a/modules/EcommerceFinance/Services/UpstreamQueryCache.php +++ b/modules/EcommerceFinance/Services/UpstreamQueryCache.php @@ -176,6 +176,18 @@ class UpstreamQueryCache return $urgent; } + // 首份快照和过期快照都标记为 urgent。对于这些请求,必须让 + // 等待最久的查询先执行;否则持续出现的新列表查询会凭借下方 + // 的类型优先级,长期挤掉同一页面的 summary/options,页面就会 + // 一直停在“列表有了,但汇总或筛选项仍 503”的半完成状态。 + if ((bool) ($a['urgent'] ?? false)) { + $oldest = ((int) ($a['seen_at'] ?? 0)) <=> ((int) ($b['seen_at'] ?? 0)); + + if ($oldest !== 0) { + return $oldest; + } + } + $priority = $this->priorityFor((string) $b['scope']) <=> $this->priorityFor((string) $a['scope']); if ($priority !== 0) { diff --git a/tests/Unit/EcommerceFinance/JianSunQueryCacheTest.php b/tests/Unit/EcommerceFinance/JianSunQueryCacheTest.php index 5b1ef408..816cfd18 100644 --- a/tests/Unit/EcommerceFinance/JianSunQueryCacheTest.php +++ b/tests/Unit/EcommerceFinance/JianSunQueryCacheTest.php @@ -162,4 +162,38 @@ class JianSunQueryCacheTest extends TestCase $this->assertSame(0, $calls); } } + + public function test_oldest_urgent_snapshot_is_not_starved_by_newer_list_queries(): void + { + config()->set('upstreams.snapshots.allow_inline_refresh', false); + $cache = app(JianSunQueryCache::class); + + $this->registerColdQuery($cache, 'goods.options'); + + $registry = Cache::get('jiansun:snapshots:active:v2'); + $oldestKey = array_key_first($registry); + $registry[$oldestKey]['seen_at'] = time() - 30; + Cache::forever('jiansun:snapshots:active:v2', $registry); + + $this->registerColdQuery($cache, 'invoice-deductions.list'); + $this->registerColdQuery($cache, 'invoice-deductions.summary'); + + $entries = $cache->activeEntries(2); + + $this->assertSame('goods.options', $entries[0]['scope']); + $this->assertContains( + $entries[1]['scope'], + ['invoice-deductions.list', 'invoice-deductions.summary'] + ); + } + + private function registerColdQuery(JianSunQueryCache $cache, string $scope): void + { + try { + $cache->remember($scope, [], fn (): array => []); + $this->fail('关闭页面内刷新时,冷查询应登记后返回暂不可用。'); + } catch (ServiceUnavailableHttpException) { + $this->assertTrue(true); + } + } }