Уведомления: непрочитанные не протухают — игрок увидит их при любом заходе

Раньше уведомления удалялись через 72 часа после создания независимо от
прочтения: кто не зашёл за 3 дня, не видел их вовсе. Теперь по времени
чистятся только прочитанные (72ч после прочтения), а от роста у
незаходящих защищает кап MAX_PER_USER=100 — при создании удаляются
старейшие сверх лимита. Механика доставки не менялась: запись в БД +
pull при заходе, SSE лишь ускоряет обновление открытых вкладок.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 04:08:00 +03:00
co-authored by Claude Fable 5
parent 1dbff7ae58
commit 5c3aa6ba69
5 changed files with 71 additions and 20 deletions
+36 -10
View File
@@ -56,23 +56,49 @@ def test_create_list_mark_read(engine):
assert after["items"][0]["read_at"] is not None
def test_purge_expired(engine):
def test_purge_removes_only_long_read(engine):
"""Протухают лишь ПРОЧИТАННЫЕ (спустя 72ч после прочтения): непрочитанное должно
дождаться игрока, сколько бы тот ни отсутствовал."""
uid = _make_user(engine, "Боб")
old = datetime.now(timezone.utc).replace(tzinfo=None) - timedelta(
hours=notification_service.RETENTION_HOURS + 1
)
with Session(engine) as s:
n = Notification(user_id=uid, type="test", title="Старое")
s.add(n)
s.commit()
s.refresh(n)
# Состарим запись за пределы окна хранения.
n.created_at = datetime.now(timezone.utc).replace(tzinfo=None) - timedelta(
hours=notification_service.RETENTION_HOURS + 1
# Старое непрочитанное, старое давно прочитанное и свежепрочитанное.
s.add(Notification(user_id=uid, type="test", title="Непрочитанное", created_at=old))
s.add(
Notification(
user_id=uid, type="test", title="Давно прочитанное", created_at=old, read_at=old
)
)
s.add(
Notification(
user_id=uid,
type="test",
title="Свежепрочитанное",
created_at=old,
read_at=datetime.now(timezone.utc).replace(tzinfo=None),
)
)
s.add(n)
s.commit()
removed = notification_service.purge_expired(s)
assert removed == 1
assert notification_service.list_for_user(s, uid)["items"] == []
titles = {n["title"] for n in notification_service.list_for_user(s, uid)["items"]}
assert titles == {"Непрочитанное", "Свежепрочитанное"}
def test_cap_per_user(engine):
"""Кап MAX_PER_USER: при создании сверх лимита удаляются старейшие."""
uid = _make_user(engine, "Копитель")
with Session(engine) as s:
for i in range(notification_service.MAX_PER_USER + 5):
notification_service.create(s, uid, type="test", title=f"n{i}")
data = notification_service.list_for_user(s, uid)
assert len(data["items"]) == notification_service.MAX_PER_USER
titles = {n["title"] for n in data["items"]}
assert "n0" not in titles # старейшие срезаны
assert f"n{notification_service.MAX_PER_USER + 4}" in titles # новейшее на месте
def test_notifications_require_auth(client: TestClient):