Files
xc_agent_platform_demo/src/server.py

84 lines
2.4 KiB
Python
Raw Normal View History

"""Minimal HTTP server for the adaptation agent (stdlib only).
Listens on PORT (default 8080). Handles SIGTERM and exits the main loop
within ~1s (platform window documented as ≤30s).
Startup: require STRATEGY_ID (Phase1 product plan — fail if missing).
"""
from __future__ import annotations
import os
import signal
import sys
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from typing import Optional
from .health import handle_get
from .strategy import require_strategy_id
_shutdown = threading.Event()
_httpd: Optional[ThreadingHTTPServer] = None
class AgentHandler(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def log_message(self, fmt: str, *args) -> None: # noqa: A003
# Avoid noisy default logging; never log env secrets.
sys.stderr.write("[http] request handled (details omitted)\n")
def do_GET(self) -> None: # noqa: N802
code, headers, body = handle_get(self.path)
self.send_response(code)
for k, v in headers.items():
self.send_header(k, v)
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_POST(self) -> None: # noqa: N802
body = b'{"error":"method_not_allowed"}'
self.send_response(405)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def _on_sigterm(signum: int, frame) -> None: # noqa: ARG001
sys.stderr.write(f"Received signal {signum}; shutting down...\n")
_shutdown.set()
httpd = _httpd
if httpd is not None:
# wake serve_forever
threading.Thread(target=httpd.shutdown, daemon=True).start()
def main() -> None:
global _httpd
require_strategy_id() # exit 1 if missing
port = int(os.environ.get("PORT", "8080"))
host = os.environ.get("HOST", "0.0.0.0")
signal.signal(signal.SIGTERM, _on_sigterm)
signal.signal(signal.SIGINT, _on_sigterm)
httpd = ThreadingHTTPServer((host, port), AgentHandler)
httpd.daemon_threads = True
_httpd = httpd
sys.stderr.write(f"Listening on {host}:{port} (GET /health, GET /status)\n")
try:
httpd.serve_forever(poll_interval=0.5)
finally:
httpd.server_close()
sys.stderr.write("Server stopped.\n")
if __name__ == "__main__":
main()