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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user