Skip to content

Commit

Permalink
Add retry logic for status code - 503 (#226)
Browse files Browse the repository at this point in the history
* add retry logic for status code - 503

* handle the attribute error by checking the error body instance is dictionary

* Update error body in test case and indent the code

* setup and changelog update
  • Loading branch information
sgandhi1311 committed Sep 13, 2023
1 parent a30c5b3 commit 510eeb0
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## 1.19.1
* Add retry logic for status code - 503 [#226](https://github.com/singer-io/tap-facebook/pull/226)

## 1.19.0
* Add conversions to insights streams [#204](https://github.com/singer-io/tap-facebook/pull/204)

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from setuptools import setup

setup(name='tap-facebook',
version='1.19.0',
version='1.19.1',
description='Singer.io tap for extracting data from the Facebook Ads API',
author='Stitch',
url='https://singer.io',
Expand Down
5 changes: 3 additions & 2 deletions tap_facebook/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ def raise_from(singer_error, fb_error):
error_message = '{}: {} Message: {}'.format(
http_method,
fb_error.http_status(),
fb_error.body().get('error', {}).get('message')
fb_error.body().get('error', {}).get('message')
if isinstance(fb_error.body(), dict) else str(fb_error.body())
)
else:
# All other facebook errors are `FacebookError`s and we handle
Expand All @@ -154,7 +155,7 @@ def should_retry_api_error(exception):
elif isinstance(exception, FacebookRequestError):
return (exception.api_transient_error()
or exception.api_error_subcode() == 99
or exception.http_status() == 500
or exception.http_status() in (500, 503)
# This subcode corresponds to a race condition between AdsInsights job creation and polling
or exception.api_error_subcode() == 33
)
Expand Down
28 changes: 28 additions & 0 deletions tests/unittests/test_retry_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,34 @@ def test_retries_on_500(self):
# 5 is the max tries specified in the tap
self.assertEquals(5, mocked_account.get_ad_creatives.call_count )

def test_retries_on_503(self):
"""`AdCreative.sync.do_request()` calls a `facebook_business` method,
`get_ad_creatives()`, to make a request to the API. We mock this
method to raise a `FacebookRequestError` with an `http_status` of
`503`.
We expect the tap to retry this request up to 5 times, which is
the current hard coded `max_tries` value.
"""

# Create the mock and force the function to throw an error
mocked_account = Mock()
mocked_account.get_ad_creatives = Mock()
mocked_account.get_ad_creatives.side_effect = FacebookRequestError(
message='',
request_context={"":Mock()},
http_status=503,
http_headers=Mock(),
body="Service Uavailable"
)

# Initialize the object and call `sync()`
ad_creative_object = AdCreative('', mocked_account, '', '')
with self.assertRaises(FacebookRequestError):
ad_creative_object.sync()
# 5 is the max tries specified in the tap
self.assertEquals(5, mocked_account.get_ad_creatives.call_count )

def test_catch_a_type_error(self):
"""`AdCreative.sync.do_request()` calls a `facebook_business` method `get_ad_creatives()`.
We want to mock this to throw a `TypeError("string indices must be integers")` and assert
Expand Down

0 comments on commit 510eeb0

Please sign in to comment.