Я думаю, у вас есть правильное представление о переосмыслении того, как задача записывает в базу данных.
Возможно, было бы целесообразно, чтобы маршрут Flask добавил задачу в очередь. Как только задача окажется в очереди, маршрут Flask может вернуться, и, таким образом, контекст веб-запроса будет закрыт.
После этого вы можете запустить еще одну python (не flask) программу в фон, который непрерывно читает из этой очереди и извлекает из нее самые новые задачи, а затем выполняет задачи и сохраняет их в базе данных.
Это можно сделать с помощью Возможно, вы уже делаете это с помощью Celery для вызова асинхронного вызова. c функция? Вот запись в блоге о том, как создать такую задачу Celery и использовать ее с Flask route https://blog.miguelgrinberg.com/post/using-celery-with-flask
Вы правы, что Flask -SQLAlchemy разрушает сеанс базы данных когда контекст веб-запроса закрывается, что происходит, когда возвращается маршрут flask.
Чтобы предотвратить закрытие сеанса Flask -SQLAlchemy, вы не должны передавать свой session
от маршрута Flask к asyn c функция сельдерея. Вместо этого вы должны «создать новый сеанс» (сделать вызов в реестре сеансов) внутри функции ceyn asyn c.
Фактически это общий принцип при использовании сеансов из SQLAlchemy в веб-приложении. Вы хотите избежать передачи объекта сеанса. SQLAlchemy продвигает этот принцип, используя шаблон реестра для создания реестра сеансов, который возвращает объект сеанса «локальный поток». Эта идея «локального потока» означает, что при получении сеанса из реестра сеансов вы гарантируете, что сеанс используется только в текущем потоке. Поскольку вы в конечном итоге создаете новый поток для выполнения длительной задачи, вы можете положиться на Реестр сеансов, который даст вам поток, на который не повлияет закрытие веб-запроса, так как веб-запрос обрабатывается в другом потоке. .
Flask -SQLAlchemy реализует этот реестр сессий по умолчанию. Например, у вас может быть задание маршрута и сельдерея, как показано ниже:
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from celery import Celery
app = Flask(__name__)
db = SQLAlchemy(app)
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'
celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
@celery.task
def do_stuff_that_takes_10_minutes(payload):
session = db.session # Gets a thread local session from the Session Registry that is different from the session obj you used in the route because this function will be executed in its own thread.
# some long running task here
return result
@app.route('/long_running_task', methods=['GET'])
def long_running_task():
session = db.session # Get a thread local session from the Session Registry that will close once this web request is complete
# use this session here and do stuff
# Call this function, which Celery will spawn a new thread to do
# Don't pass the above session object into this function, we want this
# session obj to stay only within this thread.
do_stuff_that_takes_10_minutes.delay()
return "Executing task, could take 10 minutes or more."