From c47ce83e8313395e0b927d3a1a8c52be9fa5f849 Mon Sep 17 00:00:00 2001 From: Till JS Date: Sat, 11 Apr 2026 16:45:43 +0200 Subject: [PATCH] fix(geocoding): proxy Pelias health through wrapper for monitoring blackbox-exporter can't resolve host.docker.internal on Colima, so probes of host.docker.internal:4000 and :9200 always fail. Instead, add a /health/pelias endpoint on the Hono wrapper that proxies to the Pelias API, and update prometheus.yml to probe the wrapper's proxied health endpoint. Also simplifies the status page friendly_name() now that we don't need to display the host.docker.internal targets. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/prometheus/prometheus.yml | 7 +++-- scripts/generate-status-page.sh | 13 +++----- services/mana-geocoding/src/app.ts | 4 +-- services/mana-geocoding/src/routes/health.ts | 32 ++++++++++++++++++-- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/docker/prometheus/prometheus.yml b/docker/prometheus/prometheus.yml index 68dd9aa12..d595055fb 100644 --- a/docker/prometheus/prometheus.yml +++ b/docker/prometheus/prometheus.yml @@ -292,10 +292,11 @@ scrape_configs: module: [http_2xx] static_configs: - targets: + # mana-geocoding's own health (Hono wrapper) - http://mana-geocoding:3018/health - # Pelias stack runs on host network, reached via host gateway - - http://host.docker.internal:4000/v1/status - - http://host.docker.internal:9200/_cluster/health + # Upstream Pelias health, proxied through the wrapper so the + # blackbox-exporter doesn't need host.docker.internal access. + - http://mana-geocoding:3018/health/pelias relabel_configs: - source_labels: [__address__] target_label: __param_target diff --git a/scripts/generate-status-page.sh b/scripts/generate-status-page.sh index 929fd1cde..04696d59a 100755 --- a/scripts/generate-status-page.sh +++ b/scripts/generate-status-page.sh @@ -64,15 +64,12 @@ friendly_name() { name="${name#http://}" # Interne Services (Docker-Netz): mana-geocoding:3018/health → Mana Geocoding case "$name" in + mana-geocoding:*/health/pelias) + name="Pelias (via Geocoding)" + ;; mana-geocoding:*) name="Mana Geocoding" ;; - host.docker.internal:4000*) - name="Pelias API" - ;; - host.docker.internal:9200*) - name="Pelias Elasticsearch" - ;; mana.how/*) name="${name#mana.how/}" ;; @@ -81,10 +78,8 @@ friendly_name() { name="${name%.mana.how}" ;; esac - # Entferne /health, /_cluster/health, /v1/status suffixe + # Entferne /health suffixe name="${name%/health}" - name="${name%/_cluster/health}" - name="${name%/v1/status}" # mana.how (ohne Route) → Mana [ "$name" = "mana.how" ] && name="Mana" # Erster Buchstabe groß (POSIX-kompatibel) diff --git a/services/mana-geocoding/src/app.ts b/services/mana-geocoding/src/app.ts index 27e69ea7b..8f5fed328 100644 --- a/services/mana-geocoding/src/app.ts +++ b/services/mana-geocoding/src/app.ts @@ -6,7 +6,7 @@ import { Hono } from 'hono'; import { cors } from 'hono/cors'; import type { Config } from './config'; -import { healthRoutes } from './routes/health'; +import { createHealthRoutes } from './routes/health'; import { createGeocodeRoutes } from './routes/geocode'; export function createApp(config: Config): Hono { @@ -25,7 +25,7 @@ export function createApp(config: Config): Hono { }) ); - app.route('/health', healthRoutes); + app.route('/health', createHealthRoutes(config)); app.route('/api/v1/geocode', createGeocodeRoutes(config)); return app; diff --git a/services/mana-geocoding/src/routes/health.ts b/services/mana-geocoding/src/routes/health.ts index c43276116..5ea71c50d 100644 --- a/services/mana-geocoding/src/routes/health.ts +++ b/services/mana-geocoding/src/routes/health.ts @@ -1,5 +1,33 @@ import { Hono } from 'hono'; +import type { Config } from '../config'; -export const healthRoutes = new Hono(); +export function createHealthRoutes(config: Config) { + const app = new Hono(); -healthRoutes.get('/', (c) => c.json({ status: 'ok', service: 'mana-geocoding' })); + /** Wrapper health — is our Hono server up? */ + app.get('/', (c) => c.json({ status: 'ok', service: 'mana-geocoding' })); + + /** + * Upstream Pelias health. Proxies a request to the Pelias API and + * Elasticsearch cluster health so monitoring can reach them without + * needing `extra_hosts: host.docker.internal` on the blackbox exporter. + */ + app.get('/pelias', async (c) => { + try { + // Pelias API responds to /v1/status with a JSON error for unknown + // path but a 200 means the server is alive. Any other response code + // or a timeout means Pelias is unreachable. + const res = await fetch(`${config.pelias.apiUrl}/status`, { + signal: AbortSignal.timeout(5000), + }); + if (!res.ok && res.status !== 404) { + return c.json({ status: 'degraded', upstream: res.status }, 503); + } + return c.json({ status: 'ok', upstream: 'pelias-api' }); + } catch (e) { + return c.json({ status: 'down', error: e instanceof Error ? e.message : 'unknown' }, 503); + } + }); + + return app; +}