Files
wehub-resource-sync fed8b2eed7
Backend release / release (push) Waiting to run
Bandit Security Scan / bandit_scan (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / manifest (push) Blocked by required conditions
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / manifest (push) Blocked by required conditions
Python linting / ruff (push) Waiting to run
Run python tests with pytest / Run tests and count coverage (3.12) (push) Waiting to run
React Widget Build / build (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:28:29 +08:00

52 lines
1.6 KiB
Python

"""Minimal ASGI app for the worker graceful-shutdown drain e2e.
Mirrors production (a Flask SSE generator behind a2wsgi's thread pool) without
Postgres/Redis. ``/sse`` holds the connection open like an idle subscriber;
``DRAIN_HARNESS_COOPERATIVE=1`` makes it poll the real
``application.core.shutdown.is_shutting_down`` flag (the fix), else it
reproduces the pre-fix hang.
"""
from __future__ import annotations
import os
import time
from a2wsgi import WSGIMiddleware
from flask import Flask, Response
from starlette.applications import Starlette
from starlette.routing import Mount
from application.core.shutdown import is_shutting_down
_COOPERATIVE = os.environ.get("DRAIN_HARNESS_COOPERATIVE") == "1"
_POLL_SECONDS = 1.0
_MAX_HOLD_SECONDS = 120.0
flask_app = Flask(__name__)
@flask_app.get("/health")
def health() -> Response:
return Response('{"ok": true}', mimetype="application/json")
@flask_app.get("/sse")
def sse() -> Response:
def generate():
# Emit headers immediately (like the real ": connected" frame) so the
# client establishes the stream, then hold without writing further.
yield ": connected\n\n"
deadline = time.monotonic() + _MAX_HOLD_SECONDS
while time.monotonic() < deadline:
# Cooperative variant bails on the flag; non-cooperative pins the
# a2wsgi thread to the deadline (the pre-fix hang).
if _COOPERATIVE and is_shutting_down():
break
time.sleep(_POLL_SECONDS)
return Response(generate(), mimetype="text/event-stream")
asgi_app = Starlette(routes=[Mount("/", app=WSGIMiddleware(flask_app, workers=8))])