Add MQTT webhook bridge with resilient MQTT connection handling

FastAPI service that subscribes to nearle/# on the MQTT broker and forwards
rider status, periodic logs, and profile updates to the Jupiter webhook API.

Includes fixes for a failure mode that took the bridge down silently for
~3.8 days in June 2026, during which it served HTTP 200 on / while
forwarding zero events:

- Retry MQTT connection with backoff instead of letting a single failed
  connect kill the background thread permanently.
- Subscribe inside on_connect so subscriptions are restored after an
  automatic reconnect; the session is clean, so a reconnect previously came
  back subscribed to nothing.
- Add /healthz returning 503 when MQTT is disconnected, so a monitor can
  distinguish a live bridge from a dead one.
- Replace thread-per-message forwarding with a bounded worker pool, which
  keeps memory flat when the upstream API stalls on its 5s timeout.
- Pin requirements.txt to the versions verified in production; it was
  unpinned and had already drifted to paho-mqtt 2.1.0.
- Set PYTHONUNBUFFERED so container logs are not block-buffered.
- Name the compose image nearle-api-image to match the deployed tag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-27 19:55:10 +05:30
commit 57c9e8dbbf
6 changed files with 267 additions and 0 deletions

31
docker-compose.yml Normal file
View File

@@ -0,0 +1,31 @@
services:
nearle-api:
build: .
# Pinned so `docker compose up -d --build` rebuilds the SAME tag the running
# container was created from (it was started with `docker run`, not compose).
# Without this, compose would build `nearleapi-nearle-api` and leave a
# confusing second image behind.
image: nearle-api-image
container_name: nearle_api
restart: unless-stopped
ports:
- "8000:8000"
environment:
- MQTT_BROKER=66.116.225.226
- API_STATUS_URL=https://jupiter.nearle.app/live/api/v1/utils/createriderstatus
- API_LOGS_URL=https://jupiter.nearle.app/live/api/v1/utils/createriderperiodiclog
- API_PROFILE_URL=https://jupiter.nearle.app/live/api/v1/utils/createuserredis
# /healthz returns 503 whenever the MQTT side is down, so `docker ps` shows
# "unhealthy" instead of the container looking fine while forwarding nothing.
healthcheck:
test: ["CMD-SHELL", "python -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=3).status==200 else 1)\""]
interval: 60s
timeout: 10s
retries: 3
start_period: 30s
networks:
- nearle-net
networks:
nearle-net:
external: true