Skip to content

Port api-service onto Bun.serve with geolocation through geo-ip-service - #6

Open
jim-toth wants to merge 1 commit into
masterfrom
api-service-port
Open

jim-toth wants to merge 1 commit into
masterfrom
api-service-port

Conversation

@jim-toth

Copy link
Copy Markdown
Contributor

Summary

Ports every api-service route into apps/api-service on Bun.serve, with no web framework. Responses keep the status codes, bodies, content types, CORS headers and ETags of the Express service. The relay map and fingerprint map read locations from geo-ip-service through geo-ip-client and keep serving cached locations while it is down. The MaxMind reader, the database files and the unused MongoDB connection are gone from the service. A parity harness compares the running Express service with the ported one route by route.

Changes

  • Routes: the six relay metrics routes, /relays/:fingerprint, /relays, /relay-map/, /fingerprint-map/, POST /hardware, /operators and /anyone-domains, plus /healthz.
  • src/express-compat.ts reproduces what the Express stack added:
    • Access-Control-Allow-Origin: * on every answer, and a 204 preflight for any OPTIONS request
    • weak ETags computed as Express does, and 304 for a matching If-None-Match
    • JSON as application/json; charset=utf-8, text as text/html; charset=utf-8
    • the Express not found page, and the body parser's 400 and 413 pages for POST /hardware
    • every route also matching with a trailing slash
  • POST /hardware validation returns the same error list as the express-validator rules it replaces, field paths and messages included.
  • Relay maps:
    • one batch lookup of the relays' first OR addresses through geo-ip-client, cached for GEO_IP_CACHE_TTL (default one hour)
    • stale cached locations served while geo-ip-service is unreachable; /healthz reports geoIp as degraded
    • both map routes answer 503 when no address has a location, as on a start with geo-ip-service down; the other routes do not depend on it
    • H3 cells computed in the service, as before
  • Upstream clients use fetch, and the UNS indexer database is read with Bun.SQL, so axios, pg, winston, dotenv, express and mongoose are gone. Caching, timeouts, retries and stale-on-failure behave as before.
  • Configuration keeps the existing variable names. GEO_IP_SERVICE_URL or GEO_IP_SERVICE_URL_FILE is new. A missing or invalid variable now stops startup instead of falling back.
  • dev, start and the image run Bun with --max-http-header-size=80000, matching the current job's Node setting; Bun's default is 16 KiB.
  • geo-ip-client: baseUrl may be a function called before every request, and urlFromFile(path) reads the address from a file rendered by a Nomad template. An unknown address counts as a failed request.
  • parity/parity.ts replays a fixed request set against both services and reports differences in status, body, content type, CORS headers and ETag, then lists every other header difference without failing on it. It retries to ride out data changing between the two answers, defeats the Varnish cache, sends only invalid hardware bodies, and checks a long relay request.
  • The README documents routes, configuration, outage behavior, the kept differences from Express and the parity check.

Verified

  • bun run check under Bun 1.4.3: typecheck clean, 187 tests pass, 1 skipped (it needs a real HyperBEAM node).
  • Old and new side by side locally: the Express service under Node and the ported one under Bun, both against the same stub Onionoo, VictoriaMetrics and HyperBEAM, a Postgres container, and the MaxMind test databases (read directly by the old service, served by geo-ip-service to the new one). The parity harness reported 38 of 38 requests matching. The map coordinates differ only below 1e-9, because Node and Bun round trigonometry differently. Header differences listed: X-Powered-By, Connection, Keep-Alive, and the not found page's Content-Security-Policy and X-Content-Type-Options.
  • A valid POST /hardware gave identical status, body and ETag from both.
  • With geo-ip-service stopped and the cache expired, both maps were byte for byte the same as before and /healthz reported degraded. On a restart with geo-ip-service down, both maps answered 503 and every other route answered 200. Once geo-ip-service was back, the maps recovered after the client's 30 second wait.
  • The built image answered a 77,920 byte relay request with 200, read the domains from Postgres, and stopped on SIGTERM in 0.2 seconds with exit code 0.

…elay maps through geo-ip-client, address file support in the client, and an old versus new parity harness
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant