Подскажите с реализацией обработки запроса с заменой обработчика по истечении определенного времени?

У меня есть 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 шт):

Автор решения: Roman-Stop RU aggression in UA

Вот один вариант с использованием 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())
→ Ссылка