Fix SpaceDevs rate-limiting and cache corruption from throttled responses
Don't write rate-limit/error responses to disk in next_launch_api_data, so they can't become the "most recent" cache file and cause KeyError crashes in read_cached_launches. Add defensive results-list checks in read_cached_launches and get_launches to handle any existing bad files. Drop refresh=True from the updater's get_active_crewed_flights call so the 2-hour TTL applies; the paginated spacecraft/flight crawl was running on every hourly cron job and likely causing the burst that triggered throttling. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b4f0a5bf5d
commit
9f881d7177
2 changed files with 24 additions and 11 deletions
|
|
@ -31,6 +31,9 @@ def next_launch_api_data(rocket_dir: str, limit: int = LIMIT) -> StrDict | None:
|
||||||
data: StrDict = r.json()
|
data: StrDict = r.json()
|
||||||
except requests.exceptions.JSONDecodeError:
|
except requests.exceptions.JSONDecodeError:
|
||||||
return None
|
return None
|
||||||
|
# Only persist valid launch payloads; rate-limit / error responses must not
|
||||||
|
# overwrite the cache or they become the "most recent" file.
|
||||||
|
if isinstance(data.get("results"), list):
|
||||||
open(filename, "w").write(r.text)
|
open(filename, "w").write(r.text)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
@ -328,7 +331,9 @@ def load_cached_launches(rocket_dir: str) -> StrDict | None:
|
||||||
def read_cached_launches(rocket_dir: str) -> list[Summary]:
|
def read_cached_launches(rocket_dir: str) -> list[Summary]:
|
||||||
"""Read cached launches."""
|
"""Read cached launches."""
|
||||||
data = load_cached_launches(rocket_dir)
|
data = load_cached_launches(rocket_dir)
|
||||||
return [summarize_launch(launch) for launch in data["results"]] if data else []
|
if not data or not isinstance(data.get("results"), list):
|
||||||
|
return []
|
||||||
|
return [summarize_launch(launch) for launch in data["results"]]
|
||||||
|
|
||||||
|
|
||||||
def get_launches(
|
def get_launches(
|
||||||
|
|
@ -361,10 +366,20 @@ def get_launches(
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # fallback to cached version
|
pass # fallback to cached version
|
||||||
|
|
||||||
f = existing[0][1]
|
# Find the most recent cache file that contains a valid results list.
|
||||||
|
# Older files without "results" (e.g. stale rate-limit responses) are skipped.
|
||||||
|
data = None
|
||||||
|
for _, f in existing:
|
||||||
filename = os.path.join(rocket_dir, f)
|
filename = os.path.join(rocket_dir, f)
|
||||||
data = json.load(open(filename))
|
try:
|
||||||
|
candidate = json.load(open(filename))
|
||||||
|
except (json.JSONDecodeError, OSError):
|
||||||
|
continue
|
||||||
|
if isinstance(candidate.get("results"), list):
|
||||||
|
data = candidate
|
||||||
|
break
|
||||||
|
if not data:
|
||||||
|
return []
|
||||||
upcoming = [summarize_launch(launch) for launch in data["results"]]
|
upcoming = [summarize_launch(launch) for launch in data["results"]]
|
||||||
active_crewed = get_active_crewed_flights(rocket_dir, refresh=refresh) or []
|
active_crewed = get_active_crewed_flights(rocket_dir, refresh=refresh) or []
|
||||||
by_slug = {
|
by_slug = {
|
||||||
|
|
|
||||||
|
|
@ -321,11 +321,9 @@ def update_thespacedevs(config: flask.config.Config) -> None:
|
||||||
existing_data = agenda.thespacedevs.load_cached_launches(rocket_dir)
|
existing_data = agenda.thespacedevs.load_cached_launches(rocket_dir)
|
||||||
assert existing_data
|
assert existing_data
|
||||||
|
|
||||||
# Refresh active crewed mission cache used by the launches page.
|
# Update active crewed mission cache used by the launches page.
|
||||||
# Failures are handled internally with cache fallback.
|
# Uses the 2-hour TTL; failures are handled internally with cache fallback.
|
||||||
active_crewed = agenda.thespacedevs.get_active_crewed_flights(
|
active_crewed = agenda.thespacedevs.get_active_crewed_flights(rocket_dir)
|
||||||
rocket_dir, refresh=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Always follow configured slugs
|
# Always follow configured slugs
|
||||||
follow_slugs: set[str] = set(config["FOLLOW_LAUNCHES"])
|
follow_slugs: set[str] = set(config["FOLLOW_LAUNCHES"])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue