feat: add entitlement_dirty_watch_task for fast entitlement cache refresh

Polls a marker file bumped by the Whop webhook (srebot-web) so new
purchases show up in /diagnose and /unlock within seconds instead of
waiting on the hourly entitlement_cache_task.
This commit is contained in:
FURRO404
2026-07-02 11:52:26 -07:00
parent 48a491d780
commit 5e6430daaf
+44
View File
@@ -343,6 +343,49 @@ async def before_entitlement_cache():
await get_bot().wait_until_ready()
# ── Entitlement cache refresh (webhook-triggered, fast path) ────────────────
# The Whop webhook lands in the separate srebot-webhook/srebot-web (Node)
# process, which only writes to entitlements.db — it has no direct channel
# into this process. It signals us by bumping the mtime of a marker file;
# we poll that file cheaply (a single stat call) every few seconds and do a
# full cache reload only when it actually changes, so new purchases show up
# in /diagnose and /unlock within seconds instead of waiting on the hourly
# entitlement_cache_task or an incidental refresh from another loop.
ENTITLEMENTS_DIRTY_PATH: Path = STORAGE_DIR / "entitlements.dirty"
_entitlements_dirty_mtime: float = 0.0
@tasks.loop(seconds=5)
async def entitlement_dirty_watch_task():
global _entitlements_dirty_mtime
try:
mtime = ENTITLEMENTS_DIRTY_PATH.stat().st_mtime
except FileNotFoundError:
return
if mtime <= _entitlements_dirty_mtime:
return
_entitlements_dirty_mtime = mtime
try:
await refresh_entitled_guilds(force=True)
await _record("entitlement_dirty_watch", True)
except Exception as e:
await _record("entitlement_dirty_watch", False, str(e))
raise
@entitlement_dirty_watch_task.before_loop
async def before_entitlement_dirty_watch():
await get_bot().wait_until_ready()
# Seed with the current mtime (if any) so a stale flag left over from
# before startup doesn't trigger a redundant refresh on the first tick —
# on_ready already does a forced refresh.
global _entitlements_dirty_mtime
try:
_entitlements_dirty_mtime = ENTITLEMENTS_DIRTY_PATH.stat().st_mtime
except FileNotFoundError:
pass
# ============================================================================
# POINTS ALARM TASK
# ============================================================================
@@ -693,6 +736,7 @@ async def start_all_tasks():
"""
# Phase 1: Lightweight time-check tasks
entitlement_cache_task.start()
entitlement_dirty_watch_task.start()
ldb_alarm_task.start()
squadron_stats_boundary_task.start()
points_alarm_task.start()