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) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-11 16:45:43 +02:00
parent 6977d189ab
commit c47ce83e83
4 changed files with 40 additions and 16 deletions

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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;
}