¿Cómo se encolan las solicitudes en FastAPI/Gunicorn?
Intento entender cómo FastAPI/Gunicorn maneja y encola solicitudes.
Contrato del cliente: una vez que el cliente envía una solicitud, necesita recibir una respuesta en 5 segundos. Si el cliente no recibe una respuesta dentro de 5 segundos, la solicitud ya no es útil y el cliente deja de escuchar la respuesta.
Escenario: considere el siguiente escenario:
1. Supongamos que tenemos 4 trabajadores (usando Gunicorn como administrador de procesos con UvicornWorkers; usando la imagen de docker de tiangolo)
2. El cliente envía 100 solicitudes concurrentes
3. Cada solicitud tarda 5 segundos en completarse
4. Procesamos las primeras 4 solicitudes en 5 segundos
5. Pero para ese momento, las 96 solicitudes restantes aceptadas en la cola (no estoy seguro de si ocurre la encolación o cómo funciona, agradecería si pudiera explicarlo) ya han pasado 5 segundos allí y violaron el contrato del cliente. Procesar estas 96 solicitudes es un desperdicio de recursos ya que el cliente ya no las está escuchando.
Pregunta:
1. ¿Cómo descarto estas 96 solicitudes, es decir, si cada solicitud ha estado esperando más de 5 segundos en la cola, las elimino?
davy.ai
Para implementar el requisito de descartar solicitudes que han esperado en la cola durante más de 5 segundos, podemos usar una combinación del soporte asincrónico de FastAPI y la configuración de tiempo de espera del trabajador de Gunicorn.
En primer lugar, podemos establecer un tiempo de espera para los trabajadores de Gunicorn usando la bandera
--timeout
. Por ejemplo, si queremos que un trabajador tenga tiempo de espera de 5 segundos (para que coincida con el contrato del cliente), podemos establecer--timeout 5
.A continuación, podemos agregar un middleware a nuestra aplicación FastAPI que verifique el tiempo transcurrido desde que se aceptó la solicitud (es decir, ingresó a la cola), y si supera los 5 segundos, cancele la solicitud levantando una excepción. Por ejemplo, podemos usar la biblioteca
async_timeout
y elRequestResponseEndpoint
defastapi.dependency_utils
para lograr esto:Con este middleware, cualquier solicitud que haya estado esperando en la cola durante más de 5 segundos se cancelará con una respuesta de error HTTP
408 Tiempo de espera de solicitud agotado
.Tenga en cuenta que para que esto funcione de manera efectiva, debemos configurar a los trabajadores de Gunicorn para que usen tipos de trabajadores asincrónicos (por ejemplo,
uvicorn.workers.UvicornWorker
) para que el administrador de contexto asíncrono del middleware pueda funcionar correctamente. Además, debemos ajustar el número máximo de trabajadores concurrentes (es decir, el número de banderas--workers
pasadas a Gunicorn) en función del tiempo de procesamiento promedio de la solicitud y la cantidad de núcleos de CPU disponibles en la máquina de alojamiento, para que podamos asegurarnos de que el tamaño de la cola sea manejable y el riesgo de tiempos de espera se minimice.