Skip to content

Commit

Permalink
Source FB Marketing: Handle errors without API Error Code/Messages (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristoGrab authored May 7, 2024
1 parent a330088 commit 698f543
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ data:
connectorSubtype: api
connectorType: source
definitionId: e7778cfc-e97c-4458-9ecb-b4f2bba8946c
dockerImageTag: 2.1.7
dockerImageTag: 2.1.8
dockerRepository: airbyte/source-facebook-marketing
documentationUrl: https://docs.airbyte.com/integrations/sources/facebook-marketing
githubIssueLabel: source-facebook-marketing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",]
build-backend = "poetry.core.masonry.api"

[tool.poetry]
version = "2.1.7"
version = "2.1.8"
name = "source-facebook-marketing"
description = "Source implementation for Facebook Marketing."
authors = [ "Airbyte <contact@airbyte.io>",]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def should_retry_api_error(exc):
unknown_error = exc.api_error_subcode() == FACEBOOK_UNKNOWN_ERROR_CODE
connection_reset_error = exc.api_error_code() == FACEBOOK_CONNECTION_RESET_ERROR_CODE
server_error = exc.http_status() == http.client.INTERNAL_SERVER_ERROR
service_unavailable_error = exc.http_status() == http.client.SERVICE_UNAVAILABLE
return any(
(
exc.api_transient_error(),
Expand All @@ -113,6 +114,7 @@ def should_retry_api_error(exc):
connection_reset_error,
temporary_oauth_error,
server_error,
service_unavailable_error,
)
)
return True
Expand Down Expand Up @@ -150,7 +152,7 @@ def traced_exception(fb_exception: FacebookRequestError):
Please see ../unit_tests/test_errors.py for full error examples
Please add new errors to the tests
"""
msg = fb_exception.api_error_message()
msg = fb_exception.api_error_message() or fb_exception.get_message()

if "Error validating access token" in msg:
failure_type = FailureType.config_error
Expand Down Expand Up @@ -188,9 +190,18 @@ def traced_exception(fb_exception: FacebookRequestError):
exception=fb_exception,
)

elif fb_exception.http_status() == 503:
return AirbyteTracedException(
message="The Facebook API service is temporarily unavailable. This issue should resolve itself, and does not require further action.",
internal_message=str(fb_exception),
failure_type=FailureType.transient_error,
exception=fb_exception,
)

else:
failure_type = FailureType.system_error
friendly_msg = f"Error: {fb_exception.api_error_code()}, {fb_exception.api_error_message()}."
error_code = fb_exception.api_error_code() if fb_exception.api_error_code() else fb_exception.http_status()
friendly_msg = f"Error code {error_code}: {msg}."

return AirbyteTracedException(
message=friendly_msg or msg,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@

import json
from datetime import datetime
from unittest.mock import MagicMock

import pytest
from airbyte_cdk.models import FailureType, SyncMode
from airbyte_cdk.utils.traced_exception import AirbyteTracedException
from facebook_business import FacebookAdsApi, FacebookSession
from facebook_business.exceptions import FacebookRequestError
from source_facebook_marketing.api import API
from source_facebook_marketing.streams import AdAccount, AdCreatives, AdsInsights
from source_facebook_marketing.streams.common import traced_exception

FB_API_VERSION = FacebookAdsApi.API_VERSION

Expand Down Expand Up @@ -300,6 +303,17 @@ class TestRealErrors:
# Potentially could be caused by some particular field (list of requested fields is constant).
# But since sync was successful on next attempt, then conclusion is that this is a temporal problem.
),
(
"error_503_service_unavailable",
{
"json": {
"error": {
"message": "Call was not successful",
}
},
"status_code": 503,
},
),
],
)
def test_retryable_error(self, some_config, requests_mock, name, retryable_error_response):
Expand Down Expand Up @@ -510,3 +524,35 @@ def test_adaccount_list_objects_retry(self, requests_mock, failure_response):
stream_state={},
)
assert list(record_gen) == [{"account_id": "unknown_account", "id": "act_unknown_account"}]

def test_traced_exception_with_api_error():
error = FacebookRequestError(
message="Some error occurred",
request_context={},
http_status=400,
http_headers={},
body='{"error": {"message": "Error validating access token", "code": 190}}'
)
error.api_error_message = MagicMock(return_value="Error validating access token")

result = traced_exception(error)

assert isinstance(result, AirbyteTracedException)
assert result.message == "Invalid access token. Re-authenticate if FB oauth is used or refresh access token with all required permissions"
assert result.failure_type == FailureType.config_error

def test_traced_exception_without_api_error():
error = FacebookRequestError(
message="Call was unsuccessful. The Facebook API has imploded",
request_context={},
http_status=408,
http_headers={},
body='{}'
)
error.api_error_message = MagicMock(return_value=None)

result = traced_exception(error)

assert isinstance(result, AirbyteTracedException)
assert result.message == "Error code 408: Call was unsuccessful. The Facebook API has imploded."
assert result.failure_type == FailureType.system_error
3 changes: 2 additions & 1 deletion docs/integrations/sources/facebook-marketing.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ The Facebook Marketing connector uses the `lookback_window` parameter to repeate
## Changelog

| Version | Date | Pull Request | Subject |
| :------ | :--------- | :------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|:--------|:-----------|:---------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 2.1.8 | 2024-05-07 | [37771](https://github.com/airbytehq/airbyte/pull/37771) | Handle errors without API error codes/messages |
| 2.1.7 | 2024-04-24 | [36634](https://github.com/airbytehq/airbyte/pull/36634) | Update to CDK 0.80.0 |
| 2.1.6 | 2024-04-24 | [36634](https://github.com/airbytehq/airbyte/pull/36634) | Schema descriptions |
| 2.1.5 | 2024-04-17 | [37341](https://github.com/airbytehq/airbyte/pull/37341) | Move rate limit errors to transient errors. |
Expand Down

0 comments on commit 698f543

Please sign in to comment.