fix: isolate on-chain provider outages

This commit is contained in:
Hermes Agent
2026-07-26 23:32:54 +00:00
parent a2b9b431c7
commit 2da5d20ccd
2 changed files with 50 additions and 24 deletions
+35 -24
View File
@@ -158,9 +158,30 @@ def load_history():
# ── Background scraper ────────────────────────────────────────────────────
def _scrape_onchain_sources():
"""Run independent on-chain providers so one outage cannot mask the other."""
observations = {}
errors = []
successful_sources = 0
providers = (
("LookIntoBitcoin", "scrapers.lookintobitcoin"),
("CheckOnChain", "scrapers.checkonchain"),
)
for display_name, module_name in providers:
try:
module = __import__(module_name, fromlist=["scrape_all"])
observations.update(module.scrape_all())
successful_sources += 1
except Exception as exc:
log.error("%s scraping failed: %s\n%s", display_name, exc, traceback.format_exc())
errors.append(f"{display_name}: {exc}")
return observations, errors, successful_sources
def run_scrape(force_full=False):
"""Run a scrape cycle and update cache.
By default, only refreshes fast data (price, F&G) and reuses cached on-chain data.
On-chain metrics (Playwright scrapes) only refresh if:
- force_full=True (manual full refresh)
@@ -262,30 +283,20 @@ def run_scrape(force_full=False):
if refresh_onchain:
log.info("Refreshing on-chain metrics (forced, missing, or TTL expired)...")
try:
from scrapers import lookintobitcoin
onchain = lookintobitcoin.scrape_all()
try:
from scrapers import checkonchain
onchain.update(checkonchain.scrape_all())
except Exception as e:
log.error("CheckOnChain scraping failed: %s\n%s", e, traceback.format_exc())
cycle_errors.append(f"CheckOnChain: {e}")
checkonchain_keys = {"sopr", "sellside_risk", "active_address_momentum",
"txcount_momentum", "nvt_price", "vdd_multiple"}
for key in onchain_keys:
source = "checkonchain" if key in checkonchain_keys else "lookintobitcoin"
metrics[key] = merge_observation(
existing_cache.get(key), onchain.get(key), source=source,
error="metric missing from scrape",
)
onchain, onchain_errors, successful_sources = _scrape_onchain_sources()
cycle_errors.extend(onchain_errors)
checkonchain_keys = {"sopr", "sellside_risk", "active_address_momentum",
"txcount_momentum", "nvt_price", "vdd_multiple"}
for key in onchain_keys:
source = "checkonchain" if key in checkonchain_keys else "lookintobitcoin"
metrics[key] = merge_observation(
existing_cache.get(key), onchain.get(key), source=source,
error="metric missing from scrape",
)
if successful_sources:
metrics["_onchain_timestamp"] = datetime.now(timezone.utc).isoformat()
except Exception as e:
log.error("LookIntoBitcoin scraping failed: %s\n%s", e, traceback.format_exc())
_last_error = f"On-chain scraping failed: {e}"
for k in onchain_keys:
if k in existing_cache:
metrics[k] = existing_cache[k]
elif "_onchain_timestamp" in existing_cache:
metrics["_onchain_timestamp"] = existing_cache["_onchain_timestamp"]
else:
# Reuse cached on-chain values — they're stored permanently
log.info("Reusing cached on-chain data (use Full Refresh to re-scrape)")