Skip to content

Commit

Permalink
Add option to retry on HTTP 502/503
Browse files Browse the repository at this point in the history
Handles retrying the request when Cloudflare's API returns HTTP 502/503.

Closes #124
  • Loading branch information
pims committed Jan 31, 2025
1 parent 0bb7430 commit d2aa537
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 3 deletions.
19 changes: 18 additions & 1 deletion octodns_cloudflare/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ def __init__(self, data):
CloudflareError.__init__(self, data)


class Cloudflare5xxError(CloudflareError):
def __init__(self, data):
CloudflareError.__init__(self, data)


_PROXIABLE_RECORD_TYPES = {'A', 'AAAA', 'ALIAS', 'CNAME'}


Expand Down Expand Up @@ -168,6 +173,17 @@ def _try_request(self, *args, **kwargs):
auth_tries,
)
sleep(self.retry_period)
except Cloudflare5xxError:
if tries <= 0:
raise
tries -= 1
self.log.warning(
'http 502 error encountered, pausing '
'for %ds and trying again, %d remaining',
self.retry_period,
auth_tries,
)
sleep(self.retry_period)

def _request(self, method, path, params=None, data=None):
self.log.debug('_request: method=%s, path=%s', method, path)
Expand All @@ -184,7 +200,8 @@ def _request(self, method, path, params=None, data=None):
raise CloudflareAuthenticationError(resp.json())
if resp.status_code == 429:
raise CloudflareRateLimitError(resp.json())

if resp.status_code in [502, 503]:
raise Cloudflare5xxError("http 5xx")
resp.raise_for_status()
return resp.json()

Expand Down
24 changes: 22 additions & 2 deletions tests/test_octodns_provider_cloudflare.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ def test_populate(self):

# General error
with requests_mock() as mock:
mock.get(ANY, status_code=502, text='Things caught fire')
mock.get(ANY, status_code=500, text='Things caught fire')

with self.assertRaises(HTTPError) as ctx:
zone = Zone('unit.tests.', [])
provider.populate(zone)
self.assertEqual(502, ctx.exception.response.status_code)
self.assertEqual(500, ctx.exception.response.status_code)

# Rate Limit error
with requests_mock() as mock:
Expand Down Expand Up @@ -183,6 +183,26 @@ def test_populate(self):
)
self.assertEqual('Cloudflare error', str(ctx.exception))

# 502/503 error, Cloudflare API issue
with requests_mock() as mock:
mock.get(ANY, status_code=502, text='bad gateway')

with self.assertRaises(Exception) as ctx:
zone = Zone('unit.tests.', [])
provider.populate(zone)

self.assertEqual('Cloudflare5xxError', type(ctx.exception).__name__)
self.assertEqual('Cloudflare error', str(ctx.exception))

mock.get(ANY, status_code=503, text='service unavailable')

with self.assertRaises(Exception) as ctx:
zone = Zone('unit.tests.', [])
provider.populate(zone)

self.assertEqual('Cloudflare5xxError', type(ctx.exception).__name__)
self.assertEqual('Cloudflare error', str(ctx.exception))

# Non-existent zone doesn't populate anything
with requests_mock() as mock:
mock.get(ANY, status_code=200, json=self.empty)
Expand Down

0 comments on commit d2aa537

Please sign in to comment.