Public Overpass instances go bad without warning — we just lived through a day where overpass.private.coffee (our single upstream) returned 504s after 60s while lz4.overpass-api.de served the same query in 0.6s. Survive that by trying a list of upstreams in order until one responds usefully. Server changes: - OVERPASS_URLS env — comma-separated list, tried in order. Falls back to OVERPASS_URL for backward compat, then to a built-in default pair (lz4.overpass-api.de, overpass-api.de). - Per-upstream timeout of 10s via AbortSignal.timeout, so a saturated instance fails over in seconds, not minutes. - Client abort propagation via AbortSignal.any — if the browser cancels (e.g. user panned the map), the in-flight upstream fetch is aborted too. Stops wasting upstream capacity on requests nobody wants. - Rate-limited-body detection (Overpass returns 200 with a `rate_limited` marker when throttling) triggers failover. - Per-upstream labels on overpass_upstream_requests_total and overpass_upstream_duration_seconds so the dashboard can break out health + latency by instance. Histogram buckets extended to 30s. Compose: OVERPASS_URLS passthrough with the default pair hard-wired, overridable via SOPS. Tests: 8 cases covering the new fetchWithFailover helper — happy path, 5xx failover, rate_limited failover, network error failover, timeout tagging, all-upstreams-fail, client abort stops the loop, per-attempt latency observation. Follow-ups left out of scope: - Client-side debounce (UI concern). - Moving `.observe()` after body read for accuracy in measurement. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
16 lines
439 B
TypeScript
16 lines
439 B
TypeScript
import { defineConfig, mergeConfig } from "vitest/config";
|
|
import shared from "../../vitest.shared.ts";
|
|
import { resolve } from "node:path";
|
|
|
|
// Mirror the `~` alias that React Router's runtime provides so test
|
|
// files can resolve `~/lib/...` the same way the route modules do.
|
|
export default mergeConfig(
|
|
shared,
|
|
defineConfig({
|
|
resolve: {
|
|
alias: {
|
|
"~": resolve(import.meta.dirname, "app"),
|
|
},
|
|
},
|
|
}),
|
|
);
|