Подскажите с реализацией обработки запроса с заменой обработчика по истечении определенного времени?
У меня есть flask-приложение, которое принимает запрос, выполняет на его основе функцию и отдает пользователю ее результат. Мне нужно сделать так, чтобы если функция не вернула результат в течение, допустим, пяти секунд после поступления запроса, то отправлять пользователю результат другой функции. Причем важно, чтобы изначальная функция продолжала работать и завершилась даже после завершения отправки ответа на запрос. Если изначальная функция вернет результат за пятисекундный период, нужно вернуть в ответе ее результат.
Есть ли функционал, который позволит сотворить такое?
Вот псевдокод, который примерно описывает то, что мне требуется:
@application.route("/", methods=['POST'])
def main():
executor = SomeExecutor()
# устанавливаем функцию, которая должна стриггериться по истечении 5 секунд, если main_function не успеет отработать
executor.execute_on_timeout(alternative_function, args = [request], exec_after=5)
# main_function продолжает работать даже по истечении 5 секунд
executor.execute(main_function, args = [request])
# получаем результат от одной из функций (ждем максимум 5 секунд + время выполнения alternative_function)
response = executor.result()
return response
Ответы (1 шт):
Вот один вариант с использованием concurrent.futures.wait:
from concurrent import futures
def with_delay(f, main_future, delay):
@wraps(f)
def delayed(*args, **kwargs):
try:
return main_future.result(timeout=delay)
except futures.TimeoutError as e:
return f(*args, **kwargs)
return delayed
with futures.ThreadPoolExecutor(max_workers=2) as executor:
main_future = executor.submit(main_function, request)
alt_future = executor.submit(
with_delay(alternative_function, main_future, delay=5),
request
)
finished, pending = futures.wait(
[main_future, alt_future],
return_when=futures.FIRST_COMPLETED
)
# в finished будут завершенная(-ые) задачи
# можно реализовать логику, какой результат брать, если обе завершились
# в коде ниже просто первый попавшийся
print(finished[0].result())