feat: add HTTP health endpoint on gateway port

Binds a lightweight asyncio HTTP server on the configured gateway
port (default 18790) alongside the existing agent and channel tasks.

Endpoints:
  GET /       -> "nanobot" (plain text, for service discovery)
  GET /health -> JSON with service, version, status, uptime, channels

Zero new dependencies — uses asyncio.start_server.
This commit is contained in:
rav-melisono 2026-03-29 15:31:29 +01:00
parent c8c520cc9a
commit bc357208bb

View File

@ -674,6 +674,67 @@ def gateway(
console.print(f"[green]✓[/green] Heartbeat: every {hb_cfg.interval_s}s")
async def _health_server(host: str, health_port: int):
"""Lightweight HTTP health endpoint on the gateway port."""
import json as _json
import time
start_time = time.monotonic()
async def handle(reader, writer):
try:
data = await asyncio.wait_for(reader.read(4096), timeout=5)
except (asyncio.TimeoutError, ConnectionError):
writer.close()
return
request_line = data.split(b"\r\n", 1)[0].decode("utf-8", errors="replace")
method, path = "", ""
parts = request_line.split(" ")
if len(parts) >= 2:
method, path = parts[0], parts[1]
if method == "GET" and path == "/health":
uptime_s = int(time.monotonic() - start_time)
body = _json.dumps({
"service": "nanobot",
"version": __version__,
"status": "running",
"uptime_seconds": uptime_s,
"channels": channels.enabled_channels,
})
resp = (
f"HTTP/1.0 200 OK\r\n"
f"Content-Type: application/json\r\n"
f"Content-Length: {len(body)}\r\n"
f"\r\n{body}"
)
elif method == "GET" and path == "/":
body = "nanobot"
resp = (
f"HTTP/1.0 200 OK\r\n"
f"Content-Type: text/plain\r\n"
f"Content-Length: {len(body)}\r\n"
f"\r\n{body}"
)
else:
body = "Not Found"
resp = (
f"HTTP/1.0 404 Not Found\r\n"
f"Content-Type: text/plain\r\n"
f"Content-Length: {len(body)}\r\n"
f"\r\n{body}"
)
writer.write(resp.encode())
await writer.drain()
writer.close()
server = await asyncio.start_server(handle, host, health_port)
console.print(f"[green]✓[/green] Health endpoint: http://{host}:{health_port}/health")
async with server:
await server.serve_forever()
async def run():
try:
await cron.start()
@ -681,6 +742,7 @@ def gateway(
await asyncio.gather(
agent.run(),
channels.start_all(),
_health_server(config.gateway.host, port),
)
except KeyboardInterrupt:
console.print("\nShutting down...")