Короткий ответ
Вне обработки HTTP-запроса (в отдельном потоке, фоновой задаче, планировщике) нет активного application context, который Flask-SQLAlchemy использует для доступа к конфигурации и соединению; нужно явно создать его через with app.app_context(): внутри кода, выполняемого в отдельном потоке.
Как это работает подробнее
Flask привязывает текущее приложение к контекстной локальной переменной (application context) на время обработки запроса; при запуске нового потока этот контекст не наследуется автоматически — поток не «видит» активное приложение. Flask-SQLAlchemy и другие расширения, читающие конфигурацию через current_app, без контекста выбросят RuntimeError: Working outside of application context.
Пример кода
example.py
import threading
from flask import Flask, current_app
app = Flask(__name__)
# db = SQLAlchemy(app)
def process_in_background(app, order_id):
with app.app_context():
# теперь db.session и current_app доступны корректно
order = db.session.get(Order, order_id)
order.status = "processed"
db.session.commit()
@app.route("/orders/<int:order_id>/process", methods=["POST"])
def process_order(order_id):
threading.Thread(target=process_in_background, args=(app, order_id)).start()
return {"status": "processing"}, 202Что использовать на практике
- Практика. Для фоновых операций внутри процесса нужно явно оборачивать код в
with app.app_context():; но для действительно надёжных фоновых задач (которые не должны исчезать при падении процесса) правильнее использовать отдельный воркер очереди задач (Celery/RQ) с собственной инициализацией приложения, а неthreading.Threadвнутри веб-процесса.
Подводные камни
- Риск. Передают в поток сам объект
app, но не создают контекст явно внутри потока; злоупотребляютthreading.Threadдля операций, которые по надёжности должны быть в очереди задач с повторными попытками, в результате получая потерю данных при падении процесса во время выполнения потока.