mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 04:39:39 +02:00
Cold-start fetches from the mana-geocoding container to photon-self on mana-gpu (over WSL2 mirrored networking) consistently take >10s on the first probe and ~2s once warm. The previous 8s default caused the chain to false-mark photon-self unhealthy on every cold path, leaking to public photon for the next 30s health-cache window — and pinning the public-photon answer in the 7d cache (now shortened to 1h). Also wires the docker-compose macmini env to honor PROVIDER_TIMEOUT_MS and CACHE_PUBLIC_TTL_MS overrides so production picks up the new values without a code rebuild. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
114 lines
4.2 KiB
TypeScript
114 lines
4.2 KiB
TypeScript
/**
|
|
* Application configuration loaded from environment variables.
|
|
*/
|
|
|
|
import type { ProviderName } from './providers/types';
|
|
|
|
export interface Config {
|
|
port: number;
|
|
photon: {
|
|
/** Photon base URL — public komoot endpoint by default. Used by
|
|
* the `'photon'` provider slot which always has `privacy: 'public'`. */
|
|
apiUrl: string;
|
|
};
|
|
photonSelf: {
|
|
/** Self-hosted Photon URL (e.g. `http://192.168.178.11:2322` for the
|
|
* GPU server). When set, the wrapper registers a separate
|
|
* `'photon-self'` provider with `privacy: 'local'` — eligible for
|
|
* sensitive queries. When undefined, the slot is disabled and the
|
|
* chain runs on public providers only. */
|
|
apiUrl: string | undefined;
|
|
};
|
|
nominatim: {
|
|
apiUrl: string;
|
|
userAgent: string;
|
|
/** Inter-request gap in ms. Public Nominatim policy is 1 req/sec — we
|
|
* default to 1100 ms to leave headroom against clock drift. */
|
|
intervalMs: number;
|
|
};
|
|
cors: {
|
|
origins: string[];
|
|
};
|
|
cache: {
|
|
/** Max entries in the in-memory LRU cache */
|
|
maxEntries: number;
|
|
/** Default TTL in milliseconds (24h — used for results from local
|
|
* providers like photon-self) */
|
|
ttlMs: number;
|
|
/** TTL for results that came from public APIs (Photon, Nominatim).
|
|
* Capped at 1h so a brief blip in photon-self can't pin stale
|
|
* public-fallback answers in the cache for days. The privacy
|
|
* benefit of long TTLs (fewer outbound queries) is moot now that
|
|
* photon-self serves the bulk of traffic. */
|
|
publicTtlMs: number;
|
|
};
|
|
providers: {
|
|
/** Order matters — the chain tries them top-down. Anything not in
|
|
* this list is disabled. */
|
|
enabled: ProviderName[];
|
|
/** TTL for the per-provider health cache. */
|
|
healthCacheMs: number;
|
|
/** Wall-clock timeout per provider attempt (a slow provider falls
|
|
* through to the next one). */
|
|
timeoutMs: number;
|
|
};
|
|
}
|
|
|
|
export function loadConfig(): Config {
|
|
return {
|
|
port: parseInt(process.env.PORT || '3018', 10),
|
|
photon: {
|
|
apiUrl: process.env.PHOTON_API_URL || 'https://photon.komoot.io',
|
|
},
|
|
photonSelf: {
|
|
// Opt-in: only registered when this env-var is explicitly set
|
|
// (e.g. http://192.168.178.11:2322 once the GPU server is up).
|
|
// Empty string → treated as unset so a stray "" in .env doesn't
|
|
// register a useless provider.
|
|
apiUrl: process.env.PHOTON_SELF_API_URL?.trim() || undefined,
|
|
},
|
|
nominatim: {
|
|
apiUrl: process.env.NOMINATIM_API_URL || 'https://nominatim.openstreetmap.org',
|
|
userAgent:
|
|
process.env.NOMINATIM_USER_AGENT ||
|
|
'mana-geocoding/1.0 (+https://mana.how; kontakt@memoro.ai)',
|
|
intervalMs: parseInt(process.env.NOMINATIM_INTERVAL_MS || '1100', 10),
|
|
},
|
|
cors: {
|
|
origins: (process.env.CORS_ORIGINS || 'http://localhost:5173').split(','),
|
|
},
|
|
cache: {
|
|
maxEntries: parseInt(process.env.CACHE_MAX_ENTRIES || '5000', 10),
|
|
ttlMs: parseInt(process.env.CACHE_TTL_MS || String(24 * 60 * 60 * 1000), 10),
|
|
publicTtlMs: parseInt(process.env.CACHE_PUBLIC_TTL_MS || String(60 * 60 * 1000), 10),
|
|
},
|
|
providers: {
|
|
// Default order (when GEOCODING_PROVIDERS is unset): try the
|
|
// self-hosted Photon first if it's been configured, then public
|
|
// providers as fallback. `photon-self` is silently dropped at
|
|
// chain-build time if `photonSelf.apiUrl` is undefined.
|
|
enabled: parseProviderList(process.env.GEOCODING_PROVIDERS, [
|
|
'photon-self',
|
|
'photon',
|
|
'nominatim',
|
|
]),
|
|
healthCacheMs: parseInt(process.env.PROVIDER_HEALTH_CACHE_MS || '30000', 10),
|
|
// 20 s default. Cold-start cross-LAN fetches to photon-self
|
|
// (mana-gpu over WSL2 mirrored networking) consistently take
|
|
// >10 s on the first probe and ~2 s once warm. Tighter timeouts
|
|
// false-marked photon-self unhealthy on every cold path, leaking
|
|
// to public photon for the duration of the 30 s health cache.
|
|
timeoutMs: parseInt(process.env.PROVIDER_TIMEOUT_MS || '20000', 10),
|
|
},
|
|
};
|
|
}
|
|
|
|
function parseProviderList(raw: string | undefined, fallback: ProviderName[]): ProviderName[] {
|
|
if (!raw) return fallback;
|
|
const valid: ProviderName[] = ['photon-self', 'photon', 'nominatim'];
|
|
const parsed = raw
|
|
.split(',')
|
|
.map((s) => s.trim().toLowerCase())
|
|
.filter((s): s is ProviderName => (valid as string[]).includes(s));
|
|
return parsed.length > 0 ? parsed : fallback;
|
|
}
|