Skip to content

Commit 47f5eba

Browse files
committed
Implement urllib3 native retries
1 parent bb250ee commit 47f5eba

File tree

2 files changed

+23
-27
lines changed

2 files changed

+23
-27
lines changed

winrm/protocol.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ class Protocol(object):
2626
DEFAULT_OPERATION_TIMEOUT_SEC = 20
2727
DEFAULT_MAX_ENV_SIZE = 153600
2828
DEFAULT_LOCALE = 'en-US'
29-
DEFAULT_RECONNECTION_RETRIES = 5
30-
DEFAULT_RECONNECTION_SLEEP = 5
29+
DEFAULT_RECONNECTION_RETRIES = 4
30+
DEFAULT_RECONNECTION_BACKOFF = 2.0
3131

3232
def __init__(
3333
self, endpoint, transport='plaintext', username=None,
@@ -42,7 +42,7 @@ def __init__(
4242
credssp_disable_tlsv1_2=False,
4343
send_cbt=True,
4444
reconnection_retries = DEFAULT_RECONNECTION_RETRIES,
45-
reconnection_sleep = DEFAULT_RECONNECTION_SLEEP,
45+
reconnection_backoff = DEFAULT_RECONNECTION_BACKOFF,
4646
):
4747
"""
4848
@param string endpoint: the WinRM webservice endpoint
@@ -61,8 +61,8 @@ def __init__(
6161
@param int operation_timeout_sec: maximum allowed time in seconds for any single wsman HTTP operation (default 20). Note that operation timeouts while receiving output (the only wsman operation that should take any significant time, and where these timeouts are expected) will be silently retried indefinitely. # NOQA
6262
@param string kerberos_hostname_override: the hostname to use for the kerberos exchange (defaults to the hostname in the endpoint URL)
6363
@param bool message_encryption_enabled: Will encrypt the WinRM messages if set to True and the transport auth supports message encryption (Default True).
64-
@param int reconnection_retries: Number of retries on Connection Refused
65-
@param int reconnection_sleep: Number of seconds to sleep between reconnection attempts
64+
@param int reconnection_retries: Number of retries on connection problems
65+
@param float reconnection_backoff: Number of seconds to backoff in between reconnection attempts (first sleeps X, then sleeps 2*X, then sleeps 4*X, ...)
6666
"""
6767

6868
try:
@@ -96,7 +96,7 @@ def __init__(
9696
credssp_disable_tlsv1_2=credssp_disable_tlsv1_2,
9797
send_cbt=send_cbt,
9898
reconnection_retries=reconnection_retries,
99-
reconnection_sleep=reconnection_sleep,
99+
reconnection_backoff=reconnection_backoff,
100100
)
101101

102102
self.username = username
@@ -109,7 +109,7 @@ def __init__(
109109
self.kerberos_hostname_override = kerberos_hostname_override
110110
self.credssp_disable_tlsv1_2 = credssp_disable_tlsv1_2
111111
self.reconnection_retries = reconnection_retries
112-
self.reconnection_sleep = reconnection_sleep
112+
self.reconnection_backoff = reconnection_backoff
113113

114114
def open_shell(self, i_stream='stdin', o_stream='stdout stderr',
115115
working_directory=None, env_vars=None, noprofile=False,

winrm/transport.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
from __future__ import unicode_literals
2-
import inspect
3-
import os
42
import sys
5-
import time
3+
import os
4+
import inspect
65

76
is_py2 = sys.version[0] == '2'
87

@@ -64,8 +63,8 @@ def __init__(
6463
message_encryption='auto',
6564
credssp_disable_tlsv1_2=False,
6665
send_cbt=True,
67-
reconnection_retries=5,
68-
reconnection_sleep=5,
66+
reconnection_retries=4,
67+
reconnection_backoff=2.0,
6968
):
7069
self.endpoint = endpoint
7170
self.username = username
@@ -83,7 +82,7 @@ def __init__(
8382
self.credssp_disable_tlsv1_2 = credssp_disable_tlsv1_2
8483
self.send_cbt = send_cbt
8584
self.reconnection_retries = reconnection_retries
86-
self.reconnection_sleep = reconnection_sleep
85+
self.reconnection_backoff = reconnection_backoff
8786

8887
if self.server_cert_validation not in [None, 'validate', 'ignore']:
8988
raise WinRMError('invalid server_cert_validation mode: %s' % self.server_cert_validation)
@@ -158,6 +157,16 @@ def build_session(self):
158157
settings = session.merge_environment_settings(url=self.endpoint, proxies={}, stream=None,
159158
verify=None, cert=None)
160159

160+
# Retry on connection errors, with a backoff factor
161+
retries = requests.packages.urllib3.util.retry.Retry(total=self.reconnection_retries,
162+
connect=self.reconnection_retries,
163+
status=self.reconnection_retries,
164+
read=0,
165+
backoff_factor=self.reconnection_backoff,
166+
status_forcelist=(413, 425, 429, 503))
167+
session.mount('http://', requests.adapters.HTTPAdapter(max_retries=retries))
168+
session.mount('https://', requests.adapters.HTTPAdapter(max_retries=retries))
169+
161170
# get proxy settings from env
162171
# FUTURE: allow proxy to be passed in directly to supersede this value
163172
session.proxies = settings['proxies']
@@ -266,20 +275,7 @@ def send_message(self, message):
266275

267276
def _send_message_request(self, prepared_request, message):
268277
try:
269-
270-
# Retry connection on 'Connection refused'
271-
for attempt in range(self.reconnection_retries):
272-
try:
273-
response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
274-
except requests.packages.urllib3.exceptions.NewConnectionError as e:
275-
time.sleep(self.reconnection_sleep)
276-
# except requests.exceptions.ConnectionError as e:
277-
# if attempt == 4 or 'connection refused' not in str(e).lower():
278-
# raise
279-
# time.sleep(self.reconnection_sleep)
280-
else:
281-
break
282-
278+
response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
283279
response.raise_for_status()
284280
return response
285281
except requests.HTTPError as ex:

0 commit comments

Comments
 (0)