El módulo de solicitudes de Python es simple y elegante, pero una cosa 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. Mirando 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?
python
python-requests
Kirill Zaitsev
fuente
fuente
requests.get(url, max_retries=num_max_retries, dely_between_retries=3))
just.get
yjust.post
en github.com/kootenpv/justRespuestas:
Es la
urllib3
biblioteca subyacente la que vuelve a intentarlo. Para establecer un recuento máximo de reintentos diferente, use adaptadores de transporte alternativos :El
max_retries
argumento toma un entero o unRetry()
objeto ; este último le brinda un control detallado sobre qué tipos de fallas se reintentan (un valor entero se convierte en unaRetry()
instancia que solo maneja fallas de conexión; los errores después de que se realiza una conexión no se manejan de manera predeterminada, ya que podrían provocar efectos secundarios) .Respuesta anterior, anterior a la publicación de 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:Esta constante no está documentada; úselo bajo su propio riesgo ya que las futuras versiones podrían cambiar la forma en que se maneja esto.
Actualización : y esto hizo el cambio; en la versión 1.2.1 se agregó la opción para establecer el
max_retries
parámetro en laHTTPAdapter()
clase , de modo que ahora tiene que usar adaptadores de transporte alternativos, consulte más arriba. El enfoque de parche de mono ya no funciona, a menos que también parchee losHTTPAdapter.__init__()
valores predeterminados (no se recomienda mucho).fuente
session.mount('http://', HTTPAdapter(max_retries=10))
esto funcionará para todas las conexiones http. Lo mismo con https funcionará para todas las conexiones https.http://
yhttps://
son los prefijos mínimos para usar, consulte la documentación a la que se vincula la respuesta.HTTPAdapter(max_retries=5)
solo funcionará para cierto escenario. Desde el documento de solicitudes ,Note, this applies only to failed DNS lookups, socket connections and connection timeouts, never to requests where data has made it to the server. By default, Requests does not retry failed connections.
para forzar el reintento de cualquier código de estado, consulte la respuesta de @datashaman a continuación.Retry()
para alterar qué escenarios de falla se vuelven a intentar.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: // se suspendan durante un período de tiempo antes de volver a intentarlo (hasta un total de 5 veces):
De acuerdo con la documentación para
Retry
: si el backoff_factor es 0.1 , sleep () dormirá durante [0.1s, 0.2s, 0.4s, ...] entre reintentos. También forzará un nuevo intento si el código de estado devuelto es 500 , 502 , 503 o 504 .Varias otras opciones para
Retry
permitir un control más granular:MaxRetryError
o devolver una respuesta con un código de respuesta en el rango 3xx .NB : raise_on_status es relativamente nuevo y aún no se ha convertido en una versión de urllib3 o solicitudes.Elargumento de la palabra clave raise_on_status parece haber llegado a la biblioteca estándar como máximo en python versión 3.6.Para realizar solicitudes, vuelva a intentarlo con códigos de estado HTTP específicos, use status_forcelist . Por ejemplo, status_forcelist = [503] volverá a intentar el código de estado 503 (servicio no disponible).
De forma predeterminada, el reintento solo se activa para estas condiciones:
TimeoutError
HTTPException
elevado (desde http.client en Python 3 más httplib ). Esto parece ser excepciones HTTP de bajo nivel, como URL o protocolo no formados correctamente.SocketError
ProtocolError
Tenga en cuenta que estas son todas las excepciones que impiden recibir una respuesta HTTP normal. Si cualquiera se genera la respuesta normal, sin reintento está hecho. Sin usar el status_forcelist , incluso una respuesta con el estado 500 no se volverá a intentar.
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 obliga a 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 retroceso lo suficientemente grande.
EDITADO : Importar
Retry
clase directamente desde urllib3 .fuente
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:
fuente
Después de luchar un poco con algunas de las respuestas aquí, encontré una biblioteca llamada backoff que funcionaba mejor para mi situación. Un ejemplo básico:
Todavía recomiendo darle una oportunidad a la funcionalidad nativa de la biblioteca, pero si tiene algún problema o necesita un control más amplio, el retroceso es una opción.
fuente
requests
, ¡así que funciona perfectamente!Una forma más limpia de obtener un mayor control podría ser empaquetar los elementos de reintento en una función y hacer que esa función sea recuperable usando un decorador y poner en la lista blanca las excepciones.
He creado lo mismo aquí: http://www.praddy.in/retry-decorator-whitelisted-exceptions/
Reproduciendo el código en ese enlace:
fuente