Есть ли способ глобально переопределить тайм-аут запросов?

У нас есть утилиты библиотеки запросов, замусоренной по всему нашему проекту. Недавно мы столкнулись с ошибкой в ​​одном из наших пунктов назначения, где он заморозил среднюю транзакцию и решил просто закрыть соединение.

Естественно, наше приложение последовали этому примеру.

Есть ли переменная среды или какой-либо другой способ установить тайм-аут? Даже если это значительное (скажем, 30 секунд), этого должно быть достаточно, чтобы остановить все работы от остановки из-за одной службы. Если это возможно, оно должно быть глобальным, чтобы мне не приходилось находить каждое его использование, и чтобы люди не могли забыть добавить его в будущем.

Ответ 1

К сожалению, глядя на код, нет возможности установить глобальное значение по умолчанию. Я был немного удивлен этим, так как ожидал, что это будет довольно распространенный случай. Если вы запустите запрос на добавление функции, сообщите мне об этом (например, в комментариях к этому сообщению).

Причина этого заключается в том, что такие методы, как get(...), post(...) и т.д., Являются всего лишь тонкими обертками над методом Session.request(...) (requests.get(...) создает новый однократный сеанс только для одного запроса). Этот метод принимает timeout в качестве аргумента и не проверяет внутренности Session на наличие значения, если нет аргумента тайм-аута, поэтому вы всегда должны помещать его туда вручную, как 2ps, предложенное в его ответ.

Источники:

  • requests/__init__.py - импортировать API в область действия пакета, чтобы предоставить утилиты requests.get(...) -like
  • requests.api - модуль API, импортированный в пункт выше; использовать сеансы с одним выстрелом
  • requests.sessions - Session реализация

PS. See this pull request. Disclaimer: it mine.

Ответ 2

Два способа сделать это. Это связано с некоторыми грязными патчами обезьян. Протестировано на python 3.6.

Поместите это где-нибудь в файл, например main.py, init.py или urls.py и убедитесь, что он вызывается.

Вариант 1: исправить метод запросов

import requests

def request_patch(slf, *args, **kwargs):
    print("Fix called")
    timeout = kwargs.pop('timeout', 2)
    return slf.request_orig(*args, **kwargs, timeout=timeout)

setattr(requests.sessions.Session, 'request_orig', requests.sessions.Session.request)
requests.sessions.Session.request = request_patch

Вариант 2: Запустите класс Session

import requests

class SessionTimeoutFix(requests.Session):

    def request(self, *args, **kwargs):
        print("Fix called")
        timeout = kwargs.pop('timeout', 2)
        return super().request(*args, **kwargs, timeout=timeout)

requests.sessions.Session = SessionTimeoutFix

Ответ 3

Вместо этого вы можете унаследовать класс request.Session и переписать функцию request, например, так:

HTTP_TIMEOUT = 30

class TimeoutRequestsSession(requests.Session):
    def request(self, *args, **kwargs):
        kwargs.setdefault('timeout', HTTP_TIMEOUT)
        return super(TimeoutRequestsSession, self).request(*args, **kwargs)

session = TimeoutRequestsSession()
session.get('https://www.google.com') # connection timeout is default 30s

Ответ 4

Вы можете сделать это за один вызов с помощью параметра timeout:

requests.get('http://www.google.com', timeout=10)

Параметр timeout указывает количество секунд или кортеж (время ожидания подключения, тайм-аут чтения). Вы можете больше узнать об этом здесь.

Если вы хотите сделать этот глобальный, самый простой способ - реорганизовать все вызовы в класс-оболочку и убедиться, что каждый использует класс-оболочку для вызова этой конечной точки API. Я быстро проверил код запросов и не видел использования глобального переопределения для таймаута, поскольку поведение по умолчанию - это ожидание данных.

Ответ 5

Почему нет?:

    for method in ("get", "options", "head", "post", "put", "patch", "delete"):
        setattr(
            session,
            method,
            functools.partial(getattr(session, method), timeout=timeout),
        )