mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 20:17:13 +08:00
refactor: own coalescer flush lifecycle
This commit is contained in:
+3
-2
@@ -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",
|
||||
|
||||
@@ -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 记录。
|
||||
|
||||
@@ -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 淘汰任务并消费其异常"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user