refactor: own coalescer flush lifecycle

This commit is contained in:
jxxghp
2026-08-24 03:11:49 +08:00
parent e1230c0277
commit e768eb46fe
9 changed files with 71 additions and 7 deletions
+3 -2
View File
@@ -13,8 +13,8 @@
"runtime_to_db": [],
"workflow_to_db": []
},
"edge_count": 6528,
"edge_sha256": "2e30c775e78f578d804f69972ab1348e1e9d0872b00bdbfcffad08398fae68ac",
"edge_count": 6529,
"edge_sha256": "daf8459c6194e28766d62c5f16a0e1bb64caf3f3430f51736b57da505e4401e1",
"edges": [
"app -> app.runtime",
"app -> app.runtime.compat",
@@ -6183,6 +6183,7 @@
"app.startup.initializers.modules -> app.application.security",
"app.startup.initializers.modules -> app.application.security.auth",
"app.startup.initializers.modules -> app.application.security.passkeys",
"app.startup.initializers.modules -> app.application.security.url",
"app.startup.initializers.modules -> app.application.security.user",
"app.startup.initializers.modules -> app.application.security.userconfig",
"app.startup.initializers.modules -> app.application.server",
+22
View File
@@ -171,6 +171,28 @@ class EventCoalescerTest(IsolatedAsyncioTestCase):
self.assertEqual(len(awaited), 1)
self.assertEqual(awaited[0].count, 2)
async def test_close_waits_for_started_flush_task(self):
"""窗口任务已经进入异步回调时,close 必须等待它真正结束。"""
started = asyncio.Event()
release = asyncio.Event()
async def on_flush(_summary: CoalesceSummary) -> None:
"""阻塞 flush 回调,暴露关闭与在途任务之间的时序。"""
started.set()
await release.wait()
coalescer = EventCoalescer(_TEST_WINDOW, on_flush)
await coalescer.record("k", payload="a")
await coalescer.record("k", payload="b")
await asyncio.wait_for(started.wait(), timeout=_TEST_WAIT)
close_task = asyncio.create_task(coalescer.close())
await asyncio.sleep(0)
self.assertFalse(close_task.done())
release.set()
await asyncio.wait_for(close_task, timeout=_TEST_WAIT)
async def test_on_flush_exception_is_swallowed(self):
"""
on_flush 抛异常不能影响 coalescer 自身或上层调用方,仅 debug 记录。
+19
View File
@@ -1120,6 +1120,16 @@ def _patch_module_shutdown_dependencies(monkeypatch) -> dict:
monkeypatch.setattr(modules_initializer, name, dependency)
dependencies[name] = dependency
close_image_proxy_block_log_coalescer = AsyncMock()
monkeypatch.setattr(
modules_initializer,
"close_image_proxy_block_log_coalescer",
close_image_proxy_block_log_coalescer,
)
dependencies["close_image_proxy_block_log_coalescer"] = (
close_image_proxy_block_log_coalescer
)
stop_managed_resources = AsyncMock()
monkeypatch.setattr(
modules_initializer,
@@ -1158,6 +1168,15 @@ def test_browser_sessions_close_before_managed_resources(monkeypatch) -> None:
assert calls == ["browser", "resources"]
def test_module_shutdown_waits_for_image_proxy_log_coalescer(monkeypatch) -> None:
"""模块关闭必须等待图片安全日志的在途聚合任务收口。"""
dependencies = _patch_module_shutdown_dependencies(monkeypatch)
asyncio.run(modules_initializer.stop_modules())
dependencies["close_image_proxy_block_log_coalescer"].assert_awaited_once_with()
def test_shared_http_close_waits_for_real_lru_eviction(monkeypatch):
"""最终 HTTP 关闭必须等待真实 LRU 淘汰任务并消费其异常"""