Fix API calls by all workers
Quite a complex commit by GPT. I'll rewrite it somewhen
This commit is contained in:
@@ -11,6 +11,9 @@ from apscheduler.triggers.interval import IntervalTrigger
|
||||
import requests
|
||||
from flask import Flask, jsonify
|
||||
|
||||
from .scheduler_guard import should_start_scheduler
|
||||
from .shared_cache import atomic_write_json, cache_file, load_json_if_newer
|
||||
|
||||
|
||||
@dataclass
|
||||
class Cache:
|
||||
@@ -18,6 +21,7 @@ class Cache:
|
||||
last_updated = time()
|
||||
status = None
|
||||
|
||||
|
||||
data = {
|
||||
"caches": {
|
||||
"now": Cache(),
|
||||
@@ -27,6 +31,55 @@ data = {
|
||||
"etag": ""
|
||||
}
|
||||
|
||||
_IS_WRITER = should_start_scheduler()
|
||||
_CACHE_PATH = cache_file("listenbrainz")
|
||||
_CACHE_MTIME = 0.0
|
||||
|
||||
|
||||
def refresh_cache() -> None:
|
||||
"""Refresh in-memory cache from the shared JSON file (for non-writer workers)."""
|
||||
global _CACHE_MTIME
|
||||
if _IS_WRITER:
|
||||
return
|
||||
|
||||
payload, mtime = load_json_if_newer(_CACHE_PATH, _CACHE_MTIME)
|
||||
if payload is None:
|
||||
return
|
||||
|
||||
try:
|
||||
data["etag"] = payload.get("etag", data.get("etag", ""))
|
||||
data["last_updated"] = payload.get("last_updated", data.get("last_updated", time()))
|
||||
caches = payload.get("caches", {})
|
||||
for key, cache in data.get("caches", {}).items():
|
||||
if isinstance(caches, dict) and key in caches and isinstance(caches[key], dict):
|
||||
c = caches[key]
|
||||
cache.data = c.get("data", cache.data)
|
||||
cache.last_updated = c.get("last_updated", cache.last_updated)
|
||||
cache.status = c.get("status", cache.status)
|
||||
finally:
|
||||
_CACHE_MTIME = mtime
|
||||
|
||||
|
||||
def _persist_cache() -> None:
|
||||
"""Persist current cache state to the shared JSON file (writer worker only)."""
|
||||
if not _IS_WRITER:
|
||||
return
|
||||
|
||||
payload = {
|
||||
"etag": data.get("etag", ""),
|
||||
"last_updated": data.get("last_updated", time()),
|
||||
"caches": {
|
||||
k: {
|
||||
"data": v.data,
|
||||
"last_updated": v.last_updated,
|
||||
"status": v.status,
|
||||
}
|
||||
for k, v in data.get("caches", {}).items()
|
||||
},
|
||||
}
|
||||
atomic_write_json(_CACHE_PATH, payload)
|
||||
|
||||
|
||||
def yt_cover(youtube_url):
|
||||
parsed_url = urlparse(youtube_url)
|
||||
|
||||
@@ -42,6 +95,7 @@ def yt_cover(youtube_url):
|
||||
|
||||
return f"https://img.youtube.com/vi/{video_id}/2.jpg"
|
||||
|
||||
|
||||
def parse_listens(json: dict) -> dict:
|
||||
cover_replacing = {
|
||||
"1e699948-c7c8-4bb2-9f8b-62e14b882a5d": "ca464c1d-5848-45bb-b92d-b1e4b00f9d65",
|
||||
@@ -86,7 +140,11 @@ def parse_listens(json: dict) -> dict:
|
||||
|
||||
return new_json
|
||||
|
||||
|
||||
def api_request(url: str, cache: Cache):
|
||||
changed = False
|
||||
prev_status = cache.status
|
||||
|
||||
try:
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
@@ -100,24 +158,36 @@ def api_request(url: str, cache: Cache):
|
||||
data['etag'] = md5(''.join(
|
||||
( dumps(data['caches'][x].data) for x in data['caches'] )
|
||||
).encode()).hexdigest()
|
||||
changed = True
|
||||
else:
|
||||
cache.status = f'error: {response.status_code}'
|
||||
except Exception as e:
|
||||
cache.status = f'error: {str(e)}'
|
||||
|
||||
scheduler = BackgroundScheduler()
|
||||
scheduler.add_job(
|
||||
func=lambda: api_request("https://api.listenbrainz.org/1/user/risdeveau/listens?count=5", data['caches']['listens']),
|
||||
trigger=IntervalTrigger(minutes=1),
|
||||
id='risdeveau.listenbrainz.listens',
|
||||
replace_existing=True
|
||||
)
|
||||
scheduler.add_job(
|
||||
func=lambda: api_request("https://api.listenbrainz.org/1/user/risdeveau/playing-now", data['caches']['now']),
|
||||
trigger=IntervalTrigger(seconds=15),
|
||||
id='risdeveau.listenbrainz.playing-now',
|
||||
replace_existing=True
|
||||
)
|
||||
scheduler.start()
|
||||
if prev_status != cache.status:
|
||||
changed = True
|
||||
|
||||
atexit.register(lambda: scheduler.shutdown())
|
||||
if changed:
|
||||
_persist_cache()
|
||||
|
||||
|
||||
scheduler = BackgroundScheduler()
|
||||
|
||||
if _IS_WRITER:
|
||||
scheduler.add_job(
|
||||
func=lambda: api_request("https://api.listenbrainz.org/1/user/risdeveau/listens?count=5", data['caches']['listens']),
|
||||
trigger=IntervalTrigger(minutes=1),
|
||||
id='risdeveau.listenbrainz.listens',
|
||||
replace_existing=True
|
||||
)
|
||||
scheduler.add_job(
|
||||
func=lambda: api_request("https://api.listenbrainz.org/1/user/risdeveau/playing-now", data['caches']['now']),
|
||||
trigger=IntervalTrigger(seconds=15),
|
||||
id='risdeveau.listenbrainz.playing-now',
|
||||
replace_existing=True
|
||||
)
|
||||
_persist_cache()
|
||||
scheduler.start()
|
||||
atexit.register(lambda: scheduler.shutdown())
|
||||
else:
|
||||
refresh_cache()
|
||||
|
||||
Reference in New Issue
Block a user