meal-order-manager/src/server/entrypoint.py
Adam Moussa 3e9a1c60bf
feat(api): serve meals on ECS Fargate instead of Lambda
Keep the Flask app always-on with in-process jobs so CloudFront no longer fronts a cold-start API Gateway.
2026-09-21 14:37:48 -04:00

71 lines
1.8 KiB
Python

"""Gunicorn + SQS worker in one task. Stay a parent so SIGTERM reaches both."""
from __future__ import annotations
import os
import signal
import subprocess
import sys
import time
def main() -> None:
env = os.environ.copy()
worker = subprocess.Popen(
[sys.executable, "-m", "server.worker"],
env=env,
)
gunicorn = subprocess.Popen(
[
"gunicorn",
"--bind",
"0.0.0.0:8080",
"--workers",
os.environ.get("GUNICORN_WORKERS", "2"),
"--threads",
"2",
"--timeout",
"120",
"--graceful-timeout",
"30",
"--access-logfile",
"-",
"--error-logfile",
"-",
"server.wsgi:app",
],
env=env,
)
def shutdown(signum: int, _frame) -> None:
for proc in (gunicorn, worker):
if proc.poll() is None:
proc.send_signal(signum)
signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)
while True:
g_code = gunicorn.poll()
w_code = worker.poll()
if g_code is not None:
if worker.poll() is None:
worker.terminate()
try:
worker.wait(timeout=30)
except subprocess.TimeoutExpired:
worker.kill()
sys.exit(g_code)
if w_code is not None:
if gunicorn.poll() is None:
gunicorn.terminate()
try:
gunicorn.wait(timeout=30)
except subprocess.TimeoutExpired:
gunicorn.kill()
sys.exit(w_code or 1)
time.sleep(1)
if __name__ == "__main__":
main()