#!/usr/bin/env python3 # Изменено: 2026-03-07 # HTTP-обёртка для serverless функций на Python 3.11. # Загружает handler.py из /app/function/ и вызывает handle(event) на каждый запрос. # Почему importlib: нужно загружать модуль из фиксированного пути вне sys.path. import sys import json import importlib.util from http.server import HTTPServer, BaseHTTPRequestHandler HANDLER_PATH = "/app/function/handler.py" PORT = 8080 def load_handler(): # Загружаем модуль пользователя динамически — путь известен только в runtime. spec = importlib.util.spec_from_file_location("handler", HANDLER_PATH) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) if not hasattr(module, "handle"): raise AttributeError(f"handler.py must define a 'handle(event)' function") return module.handle _handle = load_handler() class FunctionHandler(BaseHTTPRequestHandler): def log_message(self, format, *args): # Логи в stderr чтобы не мешать stdout sys.stderr.write("%s - [%s] %s\n" % ( self.address_string(), self.log_date_time_string(), format % args, )) def do_GET(self): if self.path == "/health": self._respond(200, {"status": "ok"}) else: self._respond(200, _handle({})) def do_POST(self): length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(length) try: event = json.loads(body) if body else {} except json.JSONDecodeError: # Если тело не JSON — передаём как строку, не ломаем вызов event = {"body": body.decode("utf-8", errors="replace")} result = _handle(event) self._respond(200, result) def _respond(self, status, data): body = json.dumps(data).encode("utf-8") self.send_response(status) self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) if __name__ == "__main__": server = HTTPServer(("0.0.0.0", PORT), FunctionHandler) print(f"sless runtime (python3.11) listening on :{PORT}", flush=True) server.serve_forever()