suppress periodic notifications for stale collapsed backlogs
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 16s

The backlog-collapse fix (previous commit) correctly stops the checkpoint
from falling further behind, but it was still sending the full per-game
notification for whatever it caught up on — meaning a gamer whose checkpoint
had drifted weeks behind now dumps a multi-week, game-by-game report on the
user in one message. That's not a "periodic update" anymore, just spam.

When the collapsed window exceeds 2 hours, catch the checkpoint up silently
(still fixes the drift) but skip sending the notification for it — only
report activity that's actually recent going forward.
This commit is contained in:
vrubelroman 2026-07-04 19:14:36 +00:00
parent b0173950b8
commit ad6daf2918

View file

@ -1626,6 +1626,19 @@ class LichessBot:
since_time = period_end_approx - timedelta(minutes=period_minutes) since_time = period_end_approx - timedelta(minutes=period_minutes)
logger.info(f"📌 First check: period from {since_time} to {period_end_approx}") logger.info(f"📌 First check: period from {since_time} to {period_end_approx}")
# A collapsed backlog spanning way more than a normal check window isn't
# "recent activity" anymore — dumping a multi-week, game-by-game report
# on the user reads as spam, not a periodic update. Catch the checkpoint
# up silently in that case instead of sending the full notification.
STALE_BACKLOG_THRESHOLD = timedelta(hours=2)
is_stale_backlog = (period_end_approx - since_time) > STALE_BACKLOG_THRESHOLD
if is_stale_backlog:
logger.warning(
f"⏭️ {username}: collapsed window ({since_time} to {period_end_approx}) "
f"exceeds {STALE_BACKLOG_THRESHOLD}; catching up checkpoint silently, "
f"no notification will be sent for this stale backlog"
)
since_timestamp = int(since_time.timestamp() * 1000) since_timestamp = int(since_time.timestamp() * 1000)
# Используем приблизительное время как until_timestamp # Используем приблизительное время как until_timestamp
# После получения ответа пересчитаем фактическое время # После получения ответа пересчитаем фактическое время
@ -1737,12 +1750,13 @@ class LichessBot:
logger.info(f"🔍 Activity check result for {username}: has_games={has_games} (total={total_games}), has_puzzles={has_puzzles} (total={total_puzzles})") logger.info(f"🔍 Activity check result for {username}: has_games={has_games} (total={total_games}), has_puzzles={has_puzzles} (total={total_puzzles})")
# Отправляем уведомление только если есть реальная активность. # Отправляем уведомление только если есть реальная активность и это не
# молчаливый догон устаревшего бэклога (is_stale_backlog, см. выше).
# Ошибки форматирования/отправки НЕ перехватываются здесь: они должны # Ошибки форматирования/отправки НЕ перехватываются здесь: они должны
# всплыть во внешний обработчик, чтобы чекпоинт не продвинулся и уже # всплыть во внешний обработчик, чтобы чекпоинт не продвинулся и уже
# обнаруженная активность была отправлена повторно на следующей попытке, # обнаруженная активность была отправлена повторно на следующей попытке,
# а не потеряна молча. # а не потеряна молча.
if has_games or has_puzzles: if (has_games or has_puzzles) and not is_stale_backlog:
logger.info(f"📊 Activity detected for {gamer['username']}, preparing notification...") logger.info(f"📊 Activity detected for {gamer['username']}, preparing notification...")
user_lang = self.db.get_user_language(user_id) user_lang = self.db.get_user_language(user_id)
# Label the notification with the actual queried window, not the # Label the notification with the actual queried window, not the
@ -1765,6 +1779,8 @@ class LichessBot:
logger.info(f"✅ Sent periodic notification for {gamer['username']} to user {user_id}") logger.info(f"✅ Sent periodic notification for {gamer['username']} to user {user_id}")
# Increment periodic notification counter # Increment periodic notification counter
self.counters.increment('periodic_notification') self.counters.increment('periodic_notification')
elif is_stale_backlog and (has_games or has_puzzles):
logger.info(f"⏭️ Suppressed stale backlog notification for {gamer['username']} (had activity, but window too old)")
else: else:
logger.debug(f"⏭️ No activity found for {gamer['username']} in the last {period_minutes} minutes") logger.debug(f"⏭️ No activity found for {gamer['username']} in the last {period_minutes} minutes")