From ccaa87223a3d5918599c437985375402f3c0341c Mon Sep 17 00:00:00 2001 From: WuYongJie <549727955@qq.com> Date: Mon, 3 Aug 2026 18:10:57 +0800 Subject: [PATCH 1/2] =?UTF-8?q?wip:=20=E4=BF=AE=E5=A4=8D=E4=B8=8A=E6=B8=B8?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=BF=AB=E7=85=A7=E5=AE=8C=E6=95=B4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -- 2.47.2 From 79967ed524e10aa86c02d27ae35328af5b0fc2b2 Mon Sep 17 00:00:00 2001 From: WuYongJie <549727955@qq.com> Date: Mon, 3 Aug 2026 18:20:25 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E9=98=B2=E6=AD=A2=E4=B8=8A=E6=B8=B8?= =?UTF-8?q?=E9=A6=96=E4=BB=BD=E5=BF=AB=E7=85=A7=E8=B0=83=E5=BA=A6=E9=A5=A5?= =?UTF-8?q?=E9=A5=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/UpstreamQueryCache.php | 12 +++++++ .../JianSunQueryCacheTest.php | 34 +++++++++++++++++++ 2 files changed, 46 insertions(+) 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); + } + } } -- 2.47.2