Необходимо отправить код состояния ответа сразу с FastAPI, сохраняя задания синхронно в фоновом режиме - PullRequest
0 голосов
/ 25 марта 2020

У меня очень трудоемкая задача (обработка изображений), которая получает некоторые входные данные из запроса к конечной точке FastAPI. Для того, чтобы вызывающий абонент реагировал, мне нужно отправить мгновенное ответное сообщение, например «ok», вместе с кодом состояния 201 (последний необязательный).

До сих пор я использовал это:

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()

def main_process(parameters)
...some long task

@app.post('/task')
async def do_task(reference_id: int,
              bucket: str,
              document_url: str,
              return_url: str,
              background_tasks: BackgroundTasks):

    background_tasks.add_task(main_process, bucket, document_url, reference_id, return_url)
    return 'ok'

Каждая задача main_process загружает изображение из корзины в S3, а затем выполняет некоторую обработку. Решение, показанное выше, работает нормально до тех пор, пока не достигнет примерно 10 изображений, обработанных асинхронно (с заданным asyn c def), и затем произойдет сбой.

Я также пытался увеличить некоторые параметры оружия, например, max-requests до 100, например:

gunicorn api:app -b 0.0.0.0:8000 -w 4 -k uvicorn.workers.UvicornWorker --preload --max-requests 100 --daemon

, что дало мне больше возможностей для обработки (еще 20 изображений), но все равно происходит сбой.

Я также рассматривал возможность использования Celery или какого-либо решения распределенной очереди задач, но я хочу, чтобы все было как можно проще.

Поскольку асинхронное поведение c не является критическим , но мгновенный ответ таков: возможно ли переключиться на синхронное решение, но сразу получить ответ «ок»?

1 Ответ

1 голос
/ 26 марта 2020

Нет, вам придется по-настоящему отправить задачу и делегировать ее некоторому обработчику. Такой бэкэнд может быть довольно простым, например, просто очередь задач (celery / amqp, redis, реляционная база данных, в зависимости от ваших потребностей) и по крайней мере один процесс, использующий эту очередь, выполняющий вычисления и возвращающий результат обратно в хранилище.

Когда вы отправляете запрос из своего API, одновременно генерируйте UUID и сохраняйте его вместе с заданием на расчет в очереди. Когда вы возвращаете свои быстрые 200 OK абоненту, также предоставьте им UUID их работы (если требуется). Они снова попадут в ваш API, запрашивая результат; попросите их предоставить UUID и использовать его для поиска результата в бэкэнде хранилища.

Чтобы не вычислять один и тот же запрос дважды, сгенерируйте ha sh из запроса и используйте его вместо UUID (смотреть для коллизии, вам нужны более длинные хэши). Это работает легко, если вам не нужно иметь права пользователя / изображения.

...