From 534bded5bb8325a99b19e73e956f8892d1f29b03 Mon Sep 17 00:00:00 2001 From: Sourabh Gandhi <105213416+sgandhi1311@users.noreply.github.com> Date: Mon, 15 Apr 2024 17:28:24 +0530 Subject: [PATCH] Fix for summary param error - Added retry logic (#239) * upgrade the facebook sdk version * place the facebook_business sdk locally and add retry for the summary param error * Monkey patch the original function(call) of facebook business sdk * update logger statement --- CHANGELOG.md | 3 +++ setup.py | 4 ++-- tap_facebook/__init__.py | 52 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2fe6d8f..dfbab1c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 1.20.2 + * Bump facebook_business SDK to v19.0.2 [#238](https://github.com/singer-io/tap-facebook/pull/239) + ## 1.20.1 * Bump facebook_business SDK to v19.0.0 [#238](https://github.com/singer-io/tap-facebook/pull/238) diff --git a/setup.py b/setup.py index 29e97063..81f3da87 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from setuptools import setup setup(name='tap-facebook', - version='1.20.1', + version='1.20.2', description='Singer.io tap for extracting data from the Facebook Ads API', author='Stitch', url='https://singer.io', @@ -12,8 +12,8 @@ install_requires=[ 'attrs==17.3.0', 'backoff==2.2.1', + 'facebook_business==19.0.2', 'pendulum==1.2.0', - 'facebook_business==19.0.0', 'requests==2.20.0', 'singer-python==6.0.0', ], diff --git a/tap_facebook/__init__.py b/tap_facebook/__init__.py index 6fbcebd9..b24d74de 100755 --- a/tap_facebook/__init__.py +++ b/tap_facebook/__init__.py @@ -14,6 +14,9 @@ import requests import backoff +import sys + +import re import singer import singer.metrics as metrics from singer import utils, metadata @@ -87,6 +90,55 @@ CONFIG = {} +def retry_on_summary_param_error(backoff_type, exception, **wait_gen_kwargs): + """ + At times, the Facebook Graph API exhibits erratic behavior, + triggering errors related to the Summary parameter with a status code of 400. + However, upon retrying, the API functions as expected. + """ + def log_retry_attempt(details): + _, exception, _ = sys.exc_info() + LOGGER.info('Caught Summary param error after %s tries. Waiting %s more seconds then retrying...', + details["tries"], + details["wait"]) + + def should_retry_api_error(exception): + + # Define the regular expression pattern + pattern = r'\(#100\) Cannot include [\w, ]+ in summary param because they weren\'t there while creating the report run(?:\. All available values are: )?' + if isinstance(exception, FacebookRequestError): + return (exception.http_status()==400 and re.match(pattern, exception._error['message'])) + return False + + return backoff.on_exception( + backoff_type, + exception, + jitter=None, + on_backoff=log_retry_attempt, + giveup=lambda exc: not should_retry_api_error(exc), + **wait_gen_kwargs + ) + +original_call = FacebookAdsApi.call + +@retry_on_summary_param_error(backoff.expo, (FacebookRequestError), max_tries=5, factor=5) +def call_with_retry(self, method, path, params=None, headers=None, files=None, url_override=None, api_version=None,): + """ + Adding the retry decorator on the original function call + """ + return original_call( + self, + method, + path, + params, + headers, + files, + url_override, + api_version,) + +FacebookAdsApi.call = call_with_retry + + class TapFacebookException(Exception): pass