fix(clock): dedup tasks lock bug removal
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from datetime import timedelta
|
||||
from uuid import uuid4
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
@@ -10,7 +11,9 @@ from .services.steam_store import refresh_steam_games
|
||||
# Set while a periodic refresh is queued, so there's only ever one loop running,
|
||||
# whatever the number of workers/containers trying to start it. It expires on
|
||||
# its own if the loop dies (worker killed mid-job, Redis queue flushed, ...),
|
||||
# letting the next schedule_steam_refresh() start a new one.
|
||||
# letting the next schedule_steam_refresh() start a new one. The guard holds the
|
||||
# loop id, so if it expires while the old loop is just late, the old one stops
|
||||
# at its next run (instead of 2 loops running side by side).
|
||||
STEAM_REFRESH_GUARD_KEY = "games:steam_refresh:scheduled"
|
||||
|
||||
|
||||
@@ -25,28 +28,34 @@ def _guard_timeout() -> int:
|
||||
def schedule_steam_refresh() -> bool:
|
||||
"""Start the periodic refresh loop right away, unless one is already queued.
|
||||
Safe to call from anywhere, any number of times."""
|
||||
if not cache.add(STEAM_REFRESH_GUARD_KEY, 1, timeout=_guard_timeout()):
|
||||
loop_id = uuid4().hex
|
||||
if not cache.add(STEAM_REFRESH_GUARD_KEY, loop_id, timeout=_guard_timeout()):
|
||||
return False
|
||||
|
||||
refresh_steam_games_task.enqueue()
|
||||
refresh_steam_games_task.enqueue(loop_id=loop_id)
|
||||
return True
|
||||
|
||||
|
||||
@task
|
||||
def refresh_steam_games_task(
|
||||
game_ids: list[int] | None = None, reschedule: bool = True
|
||||
game_ids: list[int] | None = None, loop_id: str | None = None
|
||||
):
|
||||
"""Refresh Steam store info, then re-enqueue itself every
|
||||
STEAM_STORE_REFRESH_MINUTES (same self-rescheduling idea as
|
||||
sync_event_game_scopes_task, no external scheduler needed).
|
||||
|
||||
reschedule=False is a one-off run (e.g. the admin action) that leaves the
|
||||
periodic loop alone."""
|
||||
Without loop_id it's a one-off run (e.g. the admin action) that leaves the
|
||||
periodic loop alone. With loop_id, it only continues while the guard still
|
||||
holds this loop_id."""
|
||||
if loop_id is not None and cache.get(STEAM_REFRESH_GUARD_KEY) != loop_id:
|
||||
# Another loop owns the guard (or it expired), stop this one
|
||||
return
|
||||
|
||||
try:
|
||||
refresh_steam_games(game_ids)
|
||||
finally:
|
||||
if reschedule:
|
||||
cache.set(STEAM_REFRESH_GUARD_KEY, 1, timeout=_guard_timeout())
|
||||
if loop_id is not None:
|
||||
cache.set(STEAM_REFRESH_GUARD_KEY, loop_id, timeout=_guard_timeout())
|
||||
refresh_steam_games_task.using(
|
||||
run_after=timezone.now() + steam_refresh_interval()
|
||||
).enqueue()
|
||||
).enqueue(loop_id=loop_id)
|
||||
|
||||
Reference in New Issue
Block a user