Skip to content
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

[ServiceBus] Improve AMQP Error handling #16427

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions sdk/servicebus/azure-servicebus/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 7.0.2 (Unreleased)

**BugFixes**

* Operations failing due to `uamqp.errors.LinkForceDetach` caused by no activity on the connection for 10 minutes will now be retried internally except for the session receiver case.
* `uamqp.errors.AMQPConnectionError` errors with condition code `amqp:unknown-error` are now categorized into `ServiceBusConnectionError` instead of the general `ServiceBusError`.

## 7.0.1 (2021-01-12)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ def _handle_amqp_exception_with_condition(
elif condition == AMQPErrorCodes.ClientError and "timed out" in str(exception):
# handle send timeout
error_cls = OperationTimeoutError
elif condition == AMQPErrorCodes.UnknownError and isinstance(exception, AMQPErrors.AMQPConnectionError):
error_cls = ServiceBusConnectionError
else:
# handle other error codes
error_cls = _ERROR_CODE_TO_ERROR_MAPPING.get(condition, ServiceBusError)
Expand Down Expand Up @@ -491,6 +493,7 @@ class AutoLockRenewTimeout(ServiceBusError):
AMQPErrorCodes.UnauthorizedAccess: ServiceBusAuthorizationError,
AMQPErrorCodes.NotImplemented: ServiceBusError,
AMQPErrorCodes.NotAllowed: ServiceBusError,
AMQPErrorCodes.LinkDetachForced: ServiceBusConnectionError,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of error was this raised as before?

Copy link
Contributor Author

@yunhaoling yunhaoling Feb 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it used to be the general ServiceBusError which would not be retried.

but after contemplating over it, I think this should be categorized into ServiceBusConnectionError and be retried internally which saves users' efforts -- users could do nothing special but retry by themselves, so we could try for them. This also aligns the behavior with the JS SDK.

however, the retry would just happen in no-session case. In session case, we don't retry on link/connection failure by design.

ERROR_CODE_MESSAGE_LOCK_LOST: MessageLockLostError,
ERROR_CODE_MESSAGE_NOT_FOUND: MessageNotFoundError,
ERROR_CODE_AUTH_FAILED: ServiceBusAuthorizationError,
Expand Down
33 changes: 33 additions & 0 deletions sdk/servicebus/azure-servicebus/tests/livetest/test_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import logging

from uamqp import errors as AMQPErrors, constants as AMQPConstants
from azure.servicebus.exceptions import (
_create_servicebus_exception,
ServiceBusConnectionError,
ServiceBusError
)


def test_link_idle_timeout():
logger = logging.getLogger("testlogger")
amqp_error = AMQPErrors.LinkDetach(AMQPConstants.ErrorCodes.LinkDetachForced, description="Details: AmqpMessageConsumer.IdleTimerExpired: Idle timeout: 00:10:00.")
sb_error = _create_servicebus_exception(logger, amqp_error)
assert isinstance(sb_error, ServiceBusConnectionError)
assert sb_error._retryable
assert sb_error._shutdown_handler


def test_unknown_connection_error():
logger = logging.getLogger("testlogger")
amqp_error = AMQPErrors.AMQPConnectionError(AMQPConstants.ErrorCodes.UnknownError)
sb_error = _create_servicebus_exception(logger, amqp_error)
assert isinstance(sb_error,ServiceBusConnectionError)
assert sb_error._retryable
assert sb_error._shutdown_handler

amqp_error = AMQPErrors.AMQPError(AMQPConstants.ErrorCodes.UnknownError)
sb_error = _create_servicebus_exception(logger, amqp_error)
assert not isinstance(sb_error,ServiceBusConnectionError)
assert isinstance(sb_error,ServiceBusError)
assert not sb_error._retryable
assert sb_error._shutdown_handler