Skip to content

Commit cae1991

Browse files
author
Anatoli Kurtsevich
authored
RAI-17360 Expanded retry mechanism to do retries on a ConnectionError (#137)
* expanded retry mechanism to do retries on ConnectionError as well * updated CHANGELOG and version for new release
1 parent 0f23579 commit cae1991

File tree

4 files changed

+25
-22
lines changed

4 files changed

+25
-22
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v0.6.16
4+
5+
* Expanded the retry mechanism for HTTP failures raised as `ConnectionError`.
6+
37
## v0.6.15
48

59
* Increase auth token expiration buffer from 5s to 60s.

railib/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
__version_info__ = (0, 6, 15)
15+
__version_info__ = (0, 6, 16)
1616
__version__ = ".".join(map(str, __version_info__))

railib/rest.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
import json
1818
import logging
1919
from os import path
20-
import socket
21-
import time
2220
from urllib.error import URLError
2321
from urllib.parse import urlencode, urlsplit, quote
2422
from urllib.request import Request, urlopen
@@ -228,11 +226,8 @@ def _urlopen_with_retry(req: Request, retries: int = 0):
228226
for attempt in range(attempts):
229227
try:
230228
return urlopen(req)
231-
except URLError as e:
232-
if isinstance(e.reason, socket.timeout):
233-
logger.warning(f"Timeout occurred (attempt {attempt + 1}/{attempts}): {req.full_url}")
234-
else:
235-
logger.warning(f"URLError occurred {e.reason} (attempt {attempt + 1}/{attempts}): {req.full_url}")
229+
except (URLError, ConnectionError) as e:
230+
logger.warning(f"URL/Connection error occured {req.full_url} (attempt {attempt + 1}/{attempts}). Error message: {str(e)}")
236231

237232
if attempt == attempts - 1:
238233
logger.error(f"Failed to connect to {req.full_url} after {attempts} attempt{'s' if attempts > 1 else ''}")

test/test_unit.py

+18-14
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ def test_validation(self):
3131
@patch('railib.rest.urlopen')
3232
class TestURLOpenWithRetry(unittest.TestCase):
3333

34+
WARNING_LOG_PREFIX = "URL/Connection error occured"
35+
ERROR_LOG_PREFIX = "Failed to connect to"
36+
3437
def test_successful_response(self, mock_urlopen):
3538
# Set up the mock urlopen to return a successful response
3639
mock_response = MagicMock()
@@ -55,7 +58,7 @@ def test_negative_retries(self, _):
5558

5659
self.assertIn("Retries must be a non-negative integer", str(e.exception))
5760

58-
def test_timeout_retry(self, mock_urlopen):
61+
def test_url_error_retry(self, mock_urlopen):
5962
# Set up the mock urlopen to raise a socket timeout error
6063
mock_urlopen.side_effect = URLError(socket.timeout())
6164

@@ -66,26 +69,27 @@ def test_timeout_retry(self, mock_urlopen):
6669

6770
self.assertEqual(mock_urlopen.call_count, 3) # Expect 1 original call and 2 calls for retries
6871
self.assertEqual(len(log.output), 4) # Expect 3 log messages for retries and 1 for failure to connect
69-
self.assertIn('Timeout occurred', log.output[0])
70-
self.assertIn('Timeout occurred', log.output[1])
71-
self.assertIn('Timeout occurred', log.output[2])
72-
self.assertIn('Failed to connect to', log.output[3])
72+
self.assertIn(TestURLOpenWithRetry.WARNING_LOG_PREFIX, log.output[0])
73+
self.assertIn(TestURLOpenWithRetry.WARNING_LOG_PREFIX, log.output[1])
74+
self.assertIn(TestURLOpenWithRetry.WARNING_LOG_PREFIX, log.output[2])
75+
self.assertIn(TestURLOpenWithRetry.ERROR_LOG_PREFIX, log.output[3])
7376

74-
def test_other_error_retry(self, mock_urlopen):
75-
# Set up the mock urlopen to raise a non-timeout URLError
76-
mock_urlopen.side_effect = URLError('Some other error')
77+
def test_connection_error_retry(self, mock_urlopen):
78+
# Set up the mock urlopen to raise a error that is subclass of ConnectonError
79+
mock_urlopen.side_effect = ConnectionResetError("connection reset by peer")
7780

7881
req = Request('https://example.com')
7982
with self.assertLogs() as log:
8083
with self.assertRaises(Exception):
81-
_urlopen_with_retry(req, retries=2)
84+
_urlopen_with_retry(req, 2)
8285

83-
self.assertEqual(mock_urlopen.call_count, 3) # Expect 3 calls for retries
86+
self.assertEqual(mock_urlopen.call_count, 3) # Expect 1 original call and 2 calls for retries
8487
self.assertEqual(len(log.output), 4) # Expect 3 log messages for retries and 1 for failure to connect
85-
self.assertIn('URLError occurred', log.output[0])
86-
self.assertIn('URLError occurred', log.output[1])
87-
self.assertIn('URLError occurred', log.output[2])
88-
self.assertIn('Failed to connect to', log.output[3])
88+
self.assertIn(TestURLOpenWithRetry.WARNING_LOG_PREFIX, log.output[0])
89+
self.assertIn(TestURLOpenWithRetry.WARNING_LOG_PREFIX, log.output[1])
90+
self.assertIn(TestURLOpenWithRetry.WARNING_LOG_PREFIX, log.output[2])
91+
self.assertIn(TestURLOpenWithRetry.ERROR_LOG_PREFIX, log.output[3])
92+
8993

9094

9195
if __name__ == '__main__':

0 commit comments

Comments
 (0)