Ответ 1
Похоже, что Teardown Callbacks будет поддерживать то, что вы хотите. И вы можете захотеть объединить его с шаблоном из запросов обратного запроса после запроса, чтобы помочь в организации кода.
Есть ли способ в Flask отправить ответ клиенту, а затем продолжить обработку? У меня есть несколько задач по ведению бухгалтерского учета, которые нужно выполнить, но я не хочу, чтобы клиент ожидал.
Обратите внимание, что это действительно очень быстрые вещи, которые я хочу сделать, создавая новый поток или используя очередь, здесь не очень уместно. (Одна из этих быстрых вещей фактически добавляет что-то в очередь заданий.)
Похоже, что Teardown Callbacks будет поддерживать то, что вы хотите. И вы можете захотеть объединить его с шаблоном из запросов обратного запроса после запроса, чтобы помочь в организации кода.
Вы можете найти пример о том, как использовать сельдерей из флакона здесь https://gist.github.com/jzempel/3201722
Суть идеи (предназначенная для каламбура) состоит в том, чтобы определить длительные бухгалтерские задачи как @celery.task и использовать apply_async 1 или задержка с точки зрения для запуска задачи
У меня была аналогичная проблема с моим блогом. Я хотел отправить уведомления по электронной почте тем, кто подписался на комментарии, когда был опубликован новый комментарий, но я не хотел, чтобы человек отправлял комментарий, ожидающий отправки всех писем, прежде чем он получит ответ.
Я использовал для этого multiprocessing.Pool
. Я запустил пул одного рабочего (этого было достаточно, небольшой сайт трафика), а затем каждый раз, когда мне нужно отправить электронное письмо, я готовлю все в функции просмотра флагов, но передаю окончательный вызов send_email
в пул через apply_async
.
Отказоустойчивые обратные вызовы не выполняются после того, как ответ был возвращен клиенту:
import flask
import time
app = flask.Flask("after_response")
@app.teardown_request
def teardown(request):
time.sleep(2)
print("teardown_request")
@app.route("/")
def home():
return "Success!\n"
if __name__ == "__main__":
app.run()
При скручивании этого вы заметите задержку в 2 с до того, как появится ответ, а не завершающий скручивание, а затем журнал 2s позже. Это также подтверждается журналами:
teardown_request
127.0.0.1 - - [25/Jun/2018 15:41:51] "GET / HTTP/1.1" 200 -
Правильный способ выполнения после ответа возвращается использовать связующее ПО WSGI, которое добавляет привязку к методу закрытия итератора ответов. Это не так просто, как декоратор teardown_request
, но он все еще довольно прямолинейный:
import traceback
from werkzeug.wsgi import ClosingIterator
class AfterResponse:
def __init__(self, app=None):
self.callbacks = []
if app:
self.init_app(app)
def __call__(self, callback):
self.callbacks.append(callback)
return callback
def init_app(self, app):
# install extension
app.after_response = self
# install middleware
app.wsgi_app = AfterResponseMiddleware(app.wsgi_app, self)
def flush(self): for fn in self.callbacks:
try:
fn()
except Exception:
traceback.print_exc()
class AfterResponseMiddleware:
def __init__(self, application, after_response_ext):
self.application = application
self.after_response_ext = after_response_ext
def __call__(self, environ, start_response):
iterator = self.application(environ, start_response)
try:
return ClosingIterator(iterator, [self.after_response_ext.flush])
except Exception:
traceback.print_exc()
return iterator
Что вы можете использовать следующим образом:
@app.after_response
def after():
time.sleep(2)
print("after_response")
Из оболочки вы сразу увидите ответ, а затем через 2 секунды последующий after_response
ударит по журналам:
127.0.0.1 - - [25/Jun/2018 15:41:51] "GET / HTTP/1.1" 200 -
after_response
Это резюме предыдущего ответа, приведенного здесь.