KOL feeds: fix dead/blocked sources, drop stale feeds (29→25)
Feed-health pass over KOL_FEEDS: - raoulpal: stale Substack (last 2024-05) → Real Vision podcast feed - dampedspring: paywalled (0 entries) → free "Damped Spring 101" Substack - unchained: Cloudflare 403 → canonical Megaphone podcast feed - lynalden: Cloudflare 202 → FeedBurner mirror - glassnode: recovered via httpx http2=True (was 403 on HTTP/1.1) - browser User-Agent + Accept headers on feed fetch - removed dead feeds with no active replacement: placeholder, dragonfly, niccarter, eugene - pin h2==4.3.0 (required by http2=True) All 25 remaining feeds verified fetching real body content; newest post per feed ≤88d. Bundles in-flight KOL-module work already in the working tree (kol_x ingest, migration 027, tests). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,9 @@ Broadcasts alert via WebSocket. Gated by user on/off toggle.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
from typing import Deque, Optional
|
||||
|
||||
@@ -40,12 +42,49 @@ _enabled: bool = False
|
||||
_recent_signals: Deque[dict] = collections.deque(maxlen=50)
|
||||
_last_fired: dict[str, Optional[datetime]] = {s: None for s in WATCH_SYMBOLS}
|
||||
|
||||
# B52: persist _enabled across process restarts without a DB migration.
|
||||
# The file survives `systemctl restart` but is cleared by OS reboots (which is
|
||||
# acceptable — an operator who reboots the server is expected to re-arm the
|
||||
# monitor). Path is configurable via env so staging vs prod can differ.
|
||||
_STATE_FILE = os.environ.get(
|
||||
"BREAKOUT_MONITOR_STATE_FILE",
|
||||
"/tmp/trumpsignal-breakout-state.json",
|
||||
)
|
||||
|
||||
|
||||
def _load_persisted_state() -> None:
|
||||
"""Read _enabled from disk on startup. Called once at module import time."""
|
||||
global _enabled
|
||||
try:
|
||||
with open(_STATE_FILE) as f:
|
||||
data = json.load(f)
|
||||
_enabled = bool(data.get("enabled", False))
|
||||
logger.info("Breakout monitor: loaded persisted state enabled=%s", _enabled)
|
||||
except FileNotFoundError:
|
||||
pass # first run — start disabled
|
||||
except Exception as exc:
|
||||
logger.warning("Breakout monitor: failed to load state file: %s", exc)
|
||||
|
||||
|
||||
def _persist_state() -> None:
|
||||
"""Write _enabled to disk so it survives process restarts."""
|
||||
try:
|
||||
with open(_STATE_FILE, "w") as f:
|
||||
json.dump({"enabled": _enabled, "updated_at": datetime.now(timezone.utc).isoformat()}, f)
|
||||
except Exception as exc:
|
||||
logger.warning("Breakout monitor: failed to persist state: %s", exc)
|
||||
|
||||
|
||||
# Load persisted state at import time (called when main.py registers the scheduler).
|
||||
_load_persisted_state()
|
||||
|
||||
|
||||
# ── Public API ────────────────────────────────────────────────────────────────
|
||||
|
||||
def set_enabled(value: bool) -> None:
|
||||
global _enabled
|
||||
_enabled = value
|
||||
_persist_state() # B52: survive restarts
|
||||
logger.info("Funding signal monitor: %s", "ENABLED" if value else "DISABLED")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user