From e1ff1c90705823d511858fc0f3200ef039ea7f5e Mon Sep 17 00:00:00 2001 From: ThearchyHelios Date: Mon, 19 Oct 2026 12:37:30 +0800 Subject: [PATCH] =?UTF-8?q?=E9=97=AE=E6=95=B0=E6=8D=AE=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E7=9A=84=E6=B8=85=E7=90=86=E9=82=A3=E4=B8=80?= =?UTF-8?q?=E6=8B=8D=E4=B8=8D=E7=BB=99=E6=97=B6=E9=97=B4=E6=97=B6=E6=8C=89?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E6=97=B6=E9=97=B4=E7=AE=97=EF=BC=9A=E8=B0=83?= =?UTF-8?q?=E5=BA=A6=E5=BE=AA=E7=8E=AF=E7=9A=84=20process=5Fdue=20?= =?UTF-8?q?=E4=B8=8D=E4=B8=80=E5=AE=9A=E7=BB=99=20now=EF=BC=8Cchat/log.pur?= =?UTF-8?q?ge=5Ftick=E3=80=81purge=20=E4=BB=A5=E5=89=8D=E6=8B=BF=20None=20?= =?UTF-8?q?=E5=8E=BB=E5=87=8F=E4=BF=9D=E7=95=99=E6=9C=9F=E5=B0=B1=E6=8A=A5?= =?UTF-8?q?=E9=94=99=EF=BC=88=E5=A4=9A=E8=BF=9B=E7=A8=8B=E7=AB=AF=E5=88=B0?= =?UTF-8?q?=E7=AB=AF=E9=87=8C=E6=9F=A5=E5=87=BA=EF=BC=89=E3=80=82=E8=A1=A5?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/chat/log.py | 9 +++++---- backend/tests/test_chat_turns.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/backend/app/chat/log.py b/backend/app/chat/log.py index 7a104110..b00e99f2 100644 --- a/backend/app/chat/log.py +++ b/backend/app/chat/log.py @@ -197,12 +197,13 @@ async def stream(turn_id: str, after: int, *, active: Callable[[], Awaitable[str yield PING -async def purge(now: datetime, *, retain_days: float = RETAIN_DAYS, limit: int = PURGE_BATCH) -> list[str]: +async def purge(now: datetime | None = None, *, retain_days: float = RETAIN_DAYS, limit: int = PURGE_BATCH) -> list[str]: """结束超过 retain_days 天的轮次整轮删事件日志(见模块说明),交回清了哪几轮。任务行、conversation_turns 那一行不动。 结束的时刻按任务的 finished_at,没记的按 updated_at。""" + from app.db.base import utcnow from app.db.models_chat import ChatTurnEvent, ChatTurnJob - cutoff = now - timedelta(days=retain_days) + cutoff = (now or utcnow()) - timedelta(days=retain_days) async with SessionLocal() as session: ended = select(ChatTurnJob.id).where(ChatTurnJob.status.in_(FINISHED), func.coalesce(ChatTurnJob.finished_at, ChatTurnJob.updated_at) < cutoff) @@ -218,8 +219,8 @@ async def purge(now: datetime, *, retain_days: float = RETAIN_DAYS, limit: int = _last_purge = 0.0 -async def purge_tick(now: datetime) -> list[str]: - """调度循环每一拍调(scheduler/loop.process_due):一小时最多清一次。""" +async def purge_tick(now: datetime | None = None) -> list[str]: + """调度循环每一拍调(scheduler/loop.process_due,那一拍不一定给 now):一小时最多清一次,不给 now 按当前时间算。""" global _last_purge if time.monotonic() - _last_purge < PURGE_EVERY_S and _last_purge: return [] diff --git a/backend/tests/test_chat_turns.py b/backend/tests/test_chat_turns.py index f5f851b3..77104fe7 100644 --- a/backend/tests/test_chat_turns.py +++ b/backend/tests/test_chat_turns.py @@ -1155,3 +1155,17 @@ async def test_a_downgraded_account_that_can_still_chat_finishes_as_who_they_are row = await _row(turn_id) assert row.status == "done" and row.answer == "华东 300。" assert seen and seen[-1].username == "bob" and seen[-1].role == "user" + + +async def test_the_cleanup_tick_without_a_time_uses_now(monkeypatch): + """调度循环那一拍不一定给 now(process_due(None)):清理按当前时间算,不报错。""" + from app.scheduler import loop + + old = await _finished_turn(days_ago=turn_log.RETAIN_DAYS + 2) + monkeypatch.setattr(turn_log, "_last_purge", 0.0) + assert old in await turn_log.purge_tick() + assert await _events(old) == [] + again = await _finished_turn(days_ago=turn_log.RETAIN_DAYS + 2) + monkeypatch.setattr(turn_log, "_last_purge", 0.0) + await loop.process_due(None) + assert await _events(again) == []