-
Notifications
You must be signed in to change notification settings - Fork 4.5k
CDK improve error handling responses #11629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CDK improve error handling responses #11629
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great initiative! I wonder if it could introduce a security concern: if response text contains sensitive information it will be displayed in the log.
airbyte-cdk/python/airbyte_cdk/sources/streams/http/exceptions.py
Outdated
Show resolved
Hide resolved
airbyte-cdk/python/airbyte_cdk/sources/streams/http/exceptions.py
Outdated
Show resolved
Hide resolved
@@ -167,7 +167,7 @@ def max_retries(self): | |||
req.status_code = HTTPStatus.TOO_MANY_REQUESTS | |||
send_mock = mocker.patch.object(requests.Session, "send", return_value=req) | |||
|
|||
with pytest.raises(UserDefinedBackoffException): | |||
with pytest.raises(UserDefinedBackoffException, match="\nRequest URL: https://test_base_url.com/\nResponse Code: 429"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you unit test the change you also made to BaseBackoffException
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added one test for DefaultBackoffExeption
but will spend some time to add a new test BaseBackoffException
I don't think API's will return any secrets in responses but we can probably think in a better solution in the future. |
Codecov Report
@@ Coverage Diff @@
## master #11629 +/- ##
=========================================
Coverage ? 88.39%
=========================================
Files ? 37
Lines ? 1637
Branches ? 0
=========================================
Hits ? 1447
Misses ? 190
Partials ? 0 Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sure to follow the README for how to bump the version and publish a new CDK version, update the changelog etc..
pass | ||
def __init__(self, request: requests.PreparedRequest, response: requests.Response): | ||
error_message = f"Request URL: {request.url}, Response Code: {response.status_code}, Response Text: {response.text}" | ||
super().__init__(error_message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you pass request=request, response=response
as named parameters here as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alafanechere I had this thought too but because we're only displaying responses from exception HTTP responses (400, 500 etc..) I'm guessing this kind of response doesn't have any sensitive information. |
Yes I agree its an unlikely situation that would mean a poor source API design. |
/publish-cdk dry-run=false
|
@@ -167,7 +167,7 @@ def max_retries(self): | |||
req.status_code = HTTPStatus.TOO_MANY_REQUESTS | |||
send_mock = mocker.patch.object(requests.Session, "send", return_value=req) | |||
|
|||
with pytest.raises(UserDefinedBackoffException): | |||
with pytest.raises(UserDefinedBackoffException, match="Request URL: https://test_base_url.com/, Response Code: 429"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can
with pytest.raises(UserDefinedBackoffException, match="Request URL: https://test_base_url.com/, Response Code: 429"): | |
with pytest.raises(UserDefinedBackoffException, match="Request URL: https://test_base_url.com/, Response Code: 429, Response Text: ?"): |
If you tested both child classes I don't think you need to test the Base.
@@ -294,6 +294,7 @@ def _send(self, request: requests.PreparedRequest, request_kwargs: Mapping[str, | |||
raise DefaultBackoffException(request=request, response=response) | |||
elif self.raise_on_http_errors: | |||
# Raise any HTTP exceptions that happened in case there were unexpected ones | |||
self.logger.error(f"Request raised an error with response: {response.text}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marcosmarxm, this log really confused me. At this point in code, there's no error to be thrown. The happy path for a response is to not require a retry whatsoever. Now I'm seeing this log in my logs that imply an error but really my stream is working just fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What
Closes #6790
Some cases Airbyte only raises the error class and doesn't print any meaningful logs.
One unit test was edited to match the output message this modification apply.
The change take places most here:
airbyte/airbyte-cdk/python/airbyte_cdk/sources/streams/http/http.py
Lines 289 to 294 in 6aa7e4c
How
HTTPError is based on IOError, for those error exceptions you need to send the message you want to print with the error log.
Recommended reading order
x.java
y.python
🚨 User Impact 🚨
Are there any breaking changes? What is the end result perceived by the user? If yes, please merge this PR with the 🚨🚨 emoji so changelog authors can further highlight this if needed.
Pre-merge Checklist
Expand the relevant checklist and delete the others.
New Connector
Community member or Airbyter
airbyte_secret
./gradlew :airbyte-integrations:connectors:<name>:integrationTest
.README.md
bootstrap.md
. See description and examplesdocs/SUMMARY.md
docs/integrations/<source or destination>/<name>.md
including changelog. See changelog exampledocs/integrations/README.md
airbyte-integrations/builds.md
Airbyter
If this is a community PR, the Airbyte engineer reviewing this PR is responsible for the below items.
/test connector=connectors/<name>
command is passing/publish
command described hereUpdating a connector
Community member or Airbyter
airbyte_secret
./gradlew :airbyte-integrations:connectors:<name>:integrationTest
.README.md
bootstrap.md
. See description and examplesdocs/integrations/<source or destination>/<name>.md
including changelog. See changelog exampleAirbyter
If this is a community PR, the Airbyte engineer reviewing this PR is responsible for the below items.
/test connector=connectors/<name>
command is passing/publish
command described hereConnector Generator
-scaffold
in their name) have been updated with the latest scaffold by running./gradlew :airbyte-integrations:connector-templates:generator:testScaffoldTemplates
then checking in your changesTests
Unit
Put your unit tests output here.
Integration
Put your integration tests output here.
Acceptance
Put your acceptance tests output here.