feat(blog): automatic primary->fallback failover for Ollama endpoint

Blog LLM client probes BLOG_OLLAMA_URL (primary, WireGuard tunnel to Mac
Studio loopback Ollama) and falls back to BLOG_OLLAMA_URL_FALLBACK
(Cloudflare tunnel) when the primary transport is unreachable. Re-probed
at startup and every 60s; prefers primary when available. Both tunnels
terminate on the Mac loopback over independent transports, so the blog
keeps reaching fo-blog regardless of which transport drops.
This commit is contained in:
Rene Fichtmueller 2026-06-04 18:28:45 +00:00
parent 3577668cf3
commit b5a961c3bd

View File

@ -14,7 +14,27 @@
import { existsSync, readFileSync, writeFileSync } from "fs";
import { join } from "path";
const OLLAMA_URL = process.env.BLOG_OLLAMA_URL || process.env.OLLAMA_URL || "http://localhost:11434";
// -- Ollama endpoint with automatic primary->fallback failover --
// Primary = BLOG_OLLAMA_URL (WireGuard tunnel to Mac Studio loopback Ollama),
// fallback = BLOG_OLLAMA_URL_FALLBACK (Cloudflare tunnel). Independent transports;
// if the primary transport drops, requests move to the backup. Re-probed every 60s.
const OLLAMA_PRIMARY = process.env.BLOG_OLLAMA_URL || process.env.OLLAMA_URL || "http://localhost:11434";
const OLLAMA_FALLBACK = process.env.BLOG_OLLAMA_URL_FALLBACK || "";
let OLLAMA_URL = OLLAMA_PRIMARY;
async function pickOllamaUrl(): Promise<void> {
for (const u of [OLLAMA_PRIMARY, OLLAMA_FALLBACK].filter(Boolean)) {
try {
const r = await fetch(`${u}/api/tags`, { signal: AbortSignal.timeout(3000) });
if (r.ok) {
if (OLLAMA_URL !== u) console.log(`[blog-llm] ollama endpoint -> ${u}`);
OLLAMA_URL = u;
return;
}
} catch { /* try next */ }
}
}
void pickOllamaUrl();
setInterval(() => { void pickOllamaUrl(); }, 60000).unref();
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || "";
const ANTHROPIC_MODEL = process.env.ANTHROPIC_MODEL || "claude-sonnet-4-20250514";
const CLAUDE_BRIDGE_URL = process.env.CLAUDE_BRIDGE_URL || "http://localhost:3250";