¿Puedo configurar max_retries para request.request?
El módulo de solicitudes de Python es simple y elegante, pero hay una cosa que me molesta. Es posible obtener un request.exception.ConnectionError con un mensaje como:
Max retries exceeded with url: ...
Esto implica que las solicitudes pueden intentar acceder a los datos varias veces. Pero no hay una sola mención de esta posibilidad en ninguna parte de los documentos. Al mirar el código fuente, no encontré ningún lugar donde pudiera alterar el valor predeterminado (presumiblemente 0).
Entonces, ¿es posible establecer de alguna manera el número máximo de reintentos para las solicitudes?
Esto no solo cambiará max_retries sino que también habilitará una estrategia de retroceso que hace que las solicitudes a todas las direcciones http:// duerman durante un período de tiempo antes de volver a intentarlo (hasta un total de 5 veces):
import requests
from requests.adapters import HTTPAdapter, Retry
s = requests.Session()
retries = Retry(total=5,
backoff_factor=0.1,
status_forcelist=[ 500, 502, 503, 504 ])
s.mount('http://', HTTPAdapter(max_retries=retries))
s.get('http://httpstat.us/500')
Según la documentación paraRetry
: si backoff_factor es 0,1 , entonces sleep() dormirá durante [0,05 s, 0,1 s, 0,2 s, 0,4 s, ...] entre reintentos. También forzará un reintento si el código de estado devuelto es 500 , 502 , 503 o 504 .
Varias otras opciones para Retry
permitir un control más granular:
- total : número total de reintentos a permitir.
- conectar : cuántos errores relacionados con la conexión volver a intentar.
- leer : cuántas veces reintentar en caso de errores de lectura.
- redirección : cuántas redirecciones realizar.
- Method_whitelist : conjunto de verbos de métodos HTTP en mayúsculas que deberíamos volver a intentar.
- status_forcelist : un conjunto de códigos de estado HTTP que debemos forzar un reintento.
- backoff_factor : un factor de retroceso que se aplicará entre intentos.
- rise_on_redirect : si, si se agota el número de redirecciones, generar un correo electrónico
MaxRetryError
o devolver una respuesta con un código de respuesta en el rango 3xx . - rise_on_status: significado similar a rise_on_redirect : si debemos generar una excepción o devolver una respuesta, si el estado cae en el rango status_forcelist y se han agotado los reintentos.
NB : rise_on_status es relativamente nuevo y aún no se ha incluido en una versión de urllib3 ni en solicitudes. El argumento de la palabra clave rise_on_status parece haber llegado a la biblioteca estándar como máximo en la versión 3.6 de Python.
Para hacer que las solicitudes se vuelvan a intentar con códigos de estado HTTP específicos, use status_forcelist . Por ejemplo, status_forcelist=[503] volverá a intentarlo con el código de estado 503 (servicio no disponible).
De forma predeterminada, el reintento solo se activa en estas condiciones:
- No se pudo obtener una conexión desde el grupo.
TimeoutError
HTTPException
planteado (de http.client en Python 3 o httplib ). Parecen ser excepciones HTTP de bajo nivel, como una URL o un protocolo no formado correctamente.SocketError
ProtocolError
Tenga en cuenta que todas estas son excepciones que impiden recibir una respuesta HTTP normal. Si se genera alguna respuesta regular, no se realiza ningún reintento. Sin utilizar status_forcelist , ni siquiera se volverá a intentar una respuesta con estado 500.
Para que se comporte de una manera más intuitiva para trabajar con una API remota o un servidor web, usaría el fragmento de código anterior, que fuerza los reintentos en los estados 500 , 502 , 503 y 504 , todos los cuales no son infrecuentes en el web y (posiblemente) recuperable dado un período de espera lo suficientemente grande.
Es la urllib3
biblioteca subyacente la que realiza el reintento. Para establecer un recuento máximo de reintentos diferente, utilice adaptadores de transporte alternativos :
from requests.adapters import HTTPAdapter
s = requests.Session()
s.mount('http://stackoverflow.com', HTTPAdapter(max_retries=5))
El max_retries
argumento toma un número entero o un Retry()
objeto ; este último le brinda un control detallado sobre qué tipos de fallas se reintentan (un valor entero se convierte en una Retry()
instancia que solo maneja fallas de conexión; los errores después de establecer una conexión no se manejan de manera predeterminada, ya que podrían generar efectos secundarios) .
Respuesta anterior, anterior al lanzamiento de las solicitudes 1.2.1 :
La requests
biblioteca realmente no hace que esto sea configurable, ni tiene la intención de hacerlo (consulte esta solicitud de extracción ). Actualmente (solicitudes 1.1), el recuento de reintentos está establecido en 0. Si realmente desea establecerlo en un valor más alto, deberá configurarlo globalmente:
import requests
requests.adapters.DEFAULT_RETRIES = 5
Esta constante no está documentada; Úselo bajo su propia responsabilidad, ya que versiones futuras podrían cambiar la forma en que se maneja esto.
Actualización : y esto cambió ; en la versión 1.2.1 se agregó la opción para configurar el max_retries
parámetro en la HTTPAdapter()
clase , por lo que ahora debe usar adaptadores de transporte alternativos, ver arriba. El enfoque de parche de mono ya no funciona, a menos que también parchee los HTTPAdapter.__init__()
valores predeterminados (no es muy recomendable).
Tenga cuidado, la respuesta de Martijn Pieters no es adecuada para la versión 1.2.1+. No puede configurarlo globalmente sin parchear la biblioteca.
Puedes hacer esto en su lugar:
import requests
from requests.adapters import HTTPAdapter
s = requests.Session()
s.mount('http://www.github.com', HTTPAdapter(max_retries=5))
s.mount('https://www.github.com', HTTPAdapter(max_retries=5))
Después de luchar un poco con algunas de las respuestas aquí, encontré una biblioteca llamada backoff que funcionó mejor para mi situación. Un ejemplo básico:
import backoff
@backoff.on_exception(
backoff.expo,
requests.exceptions.RequestException,
max_tries=5,
giveup=lambda e: e.response is not None and e.response.status_code < 500
)
def publish(self, data):
r = requests.post(url, timeout=10, json=data)
r.raise_for_status()
Aún así recomendaría darle una oportunidad a la funcionalidad nativa de la biblioteca, pero si tiene algún problema o necesita un control más amplio, retroceder es una opción.
Puede utilizar la biblioteca de solicitudes para realizar todo de una sola vez. El siguiente código se reintentará 3 veces si recibe el código de estado 429,500,502,503 o 504, cada vez con un retraso mayor establecido a través de "backoff_factor". Consulte https://findwork.dev/blog/advanced-usage-python-requests-timeouts-retries-hooks/ para obtener un buen tutorial.
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
method_whitelist=["HEAD", "GET", "OPTIONS"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
http = requests.Session()
http.mount("https://", adapter)
http.mount("http://", adapter)
response = http.get("https://en.wikipedia.org/w/api.php")