Skip to content

Commit

Permalink
[core-amqp][service-bus] Prunes core-amqp public API and move Service…
Browse files Browse the repository at this point in the history
…BusError.reason to ServiceBusError.code (Azure#12499)

This change updates the `ServiceBusError.code` field to match what was the `ServiceBusError.reason` field.

This allows us to remove the `MessagingErrorCodes` from the public interface, which we don't see as providing value above and beyond what the `ServiceBusCodes` provides.
  • Loading branch information
chradek authored Nov 12, 2020
1 parent 3d7ae46 commit a5ba074
Show file tree
Hide file tree
Showing 18 changed files with 53 additions and 273 deletions.
12 changes: 8 additions & 4 deletions sdk/core/core-amqp/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
# Release History

## 2.0.0 (2020-11-10)
## 2.0.0 (2020-11-12)

- This release marks the general availability of the `@azure/core-amqp` version 2 package.

### Breaking changes

- Continuing our work to clean the public API surface that we started in 2.0.0-beta.1, `DataTransformer` and `DefaultDataTransformer` are no longer exported.
`dataTransformer` has been removed from `ConnectionContextBase` and `ConnectionContextBaseParameters`.
This allows us to consider other forms of implementing serializers in the future.
- Continuing our work to clean the public API surface that we started in 2.0.0-beta.1 we no longer export

- `DataTransformer` and `DefaultDataTransformer`.
`dataTransformer` has been removed from `ConnectionContextBase` and `ConnectionContextBaseParameters`.
This allows us to consider other forms of implementing serializers in the future.
- `ConditionStatusMapper` and `MessagingErrorCodes` as these are only used internally by this package.

- Previously, `ConnectionConfig.validate()` overridden entityPath if `undefined` with `String(undefined) = "undefined"`. This has been updated to retain `undefined` in the validation.
[PR 12321](https://github.com/Azure/azure-sdk-for-js/pull/12321)

Expand Down
49 changes: 1 addition & 48 deletions sdk/core/core-amqp/review/core-amqp.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,50 +157,6 @@ export enum ConditionErrorNameMapper {
"system:error" = "SystemError"
}

// @public
export enum ConditionStatusMapper {
// (undocumented)
"amqp:link:message-size-exceeded" = 403,
// (undocumented)
"amqp:link:stolen" = 410,
// (undocumented)
"amqp:not-allowed" = 400,
// (undocumented)
"amqp:not-found" = 404,
// (undocumented)
"amqp:not-implemented" = 501,
// (undocumented)
"amqp:resource-limit-exceeded" = 403,
// (undocumented)
"amqp:unauthorized-access" = 401,
// (undocumented)
"com.microsoft:argument-error" = 400,
// (undocumented)
"com.microsoft:argument-out-of-range" = 400,
// (undocumented)
"com.microsoft:entity-already-exists" = 409,
// (undocumented)
"com.microsoft:entity-disabled" = 400,
// (undocumented)
"com.microsoft:message-lock-lost" = 410,
// (undocumented)
"com.microsoft:no-matching-subscription" = 500,
// (undocumented)
"com.microsoft:partition-not-owned" = 410,
// (undocumented)
"com.microsoft:publisher-revoked" = 401,
// (undocumented)
"com.microsoft:server-busy" = 503,
// (undocumented)
"com.microsoft:session-cannot-be-locked" = 410,
// (undocumented)
"com.microsoft:session-lock-lost" = 410,
// (undocumented)
"com.microsoft:store-lock-lost" = 410,
// (undocumented)
"com.microsoft:timeout" = 408
}

// @public
export interface ConnectionConfig {
connectionString: string;
Expand Down Expand Up @@ -444,7 +400,7 @@ export const logger: import("@azure/logger").AzureLogger;
export class MessagingError extends Error {
constructor(message: string, originalError?: Error);
address?: string;
code?: MessagingErrorCodes | string;
code?: string;
errno?: number | string;
info?: any;
name: string;
Expand All @@ -453,9 +409,6 @@ export class MessagingError extends Error {
syscall?: string;
}

// @public
export type MessagingErrorCodes = "AddressAlreadyInUseError" | "ArgumentError" | "ArgumentOutOfRangeError" | "ConnectionForcedError" | "ConnectionRedirectError" | "DecodeError" | "DetachForcedError" | "ErrantLinkError" | "FrameSizeTooSmallError" | "FramingError" | "HandleInUseError" | "IllegalStateError" | "InternalServerError" | "InvalidFieldError" | "InvalidOperationError" | "LinkRedirectError" | "MessageLockLostError" | "MessageNotFoundError" | "MessageTooLargeError" | "MessageWaitTimeout" | "MessagingEntityAlreadyExistsError" | "MessagingEntityDisabledError" | "MessagingEntityNotFoundError" | "NoMatchingSubscriptionError" | "NotImplementedError" | "OperationCancelledError" | "OperationTimeoutError" | "PartitionNotOwnedError" | "PreconditionFailedError" | "PublisherRevokedError" | "QuotaExceededError" | "ReceiverDisconnectedError" | "RelayNotFoundError" | "ResourceDeletedError" | "ResourceLockedError" | "SenderBusyError" | "ServerBusyError" | "ServiceCommunicationError" | "ServiceUnavailableError" | "SessionCannotBeLockedError" | "SessionLockLostError" | "SessionWindowViolationError" | "StoreLockLostError" | "SystemError" | "TransferLimitExceededError" | "UnattachedHandleError" | "UnauthorizedError";

// @public
export interface NetworkSystemError {
// (undocumented)
Expand Down
162 changes: 3 additions & 159 deletions sdk/core/core-amqp/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { isNode, isNumber, isString } from "../src/util/utils";
/**
* Maps the conditions to the numeric AMQP Response status codes.
* @enum {ConditionStatusMapper}
* @internal
* @ignore
*/
export enum ConditionStatusMapper {
"com.microsoft:timeout" = AmqpResponseStatusCode.RequestTimeout,
Expand Down Expand Up @@ -467,164 +469,6 @@ const systemErrorFieldsToCopy: (keyof Omit<NetworkSystemError, "name" | "message
"syscall"
];

/**
* AMQP messaging error codes
*
* AddressAlreadyInUseError: the address is already in use.
* ArgumentError: an incorrect argument was received.
* ArgumentOutOfRangeError: an argument has a value that is out of the admissible range.
* ConnectionForcedError: an operator intervened to close the connection for some reason.
* ConnectionRedirectError: the container is no longer available on the current connection.
* DecodeError: data could not be decoded.
* DetachForcedError: an operator intervened to detach for some reason.
* ErrantLinkError: input was received for a link that was detached with an error.
* FrameSizeTooSmallError: the peer cannot send a frame because the smallest encoding of the performative with the currently valid values would be too large to fit within a frame of the agreed maximum frame size.
* FramingError: a valid frame header cannot be formed from the incoming byte stream.
* HandleInUseError: an attach was received using a handle that is already in use for an attached link a frame (other than attach) was received referencing a handle which is not
* IllegalStateError: the peer sent a frame that is not permitted in the current state.
* InternalServerError: an internal server error occurred. You may have found a bug?
* InvalidFieldError: an invalid field was passed in a frame body, and the operation could not proceed.
* InvalidOperationError: an operation is attempted but is not allowed.
* LinkRedirectError: the address provided cannot be resolved to a terminus at the current container.
* MessageLockLostError: the lock on the message is lost.
* MessageNotFoundError: message is not found.
* MessageTooLargeError: the message sent is too large: the maximum size is 256Kb.
* MessageWaitTimeout: no new messages are received for the specified time.
* MessagingEntityAlreadyExistsError: an attempt is made to create an entity that already exists.
* MessagingEntityDisabledError: trying to access/connect to a disabled messaging entity.
* MessagingEntityNotFoundError: the messaging entity does not exist.
* NoMatchingSubscriptionError: a matching subscription is not found.
* NotImplementedError: a feature is not implemented yet but the placeholder is present.
* OperationCancelledError: server cancels the operation due to an internal issue.
* OperationTimeoutError: the service fails to respond within a given timeframe.
* PartitionNotOwnedError: an attempt is made to access a partition that is not owned by the requesting entity.
* PreconditionFailedError: a condition that should have been met in order to execute an operation was not.
* PublisherRevokedError: access to publisher has been revoked.
* QuotaExceededError: The the Azure EventHub/ServiceBus quota has been exceeded.
* ReceiverDisconnectedError: two or more instances connect to the same partition with different epoch values.
* RelayNotFoundError: relay is not found.
* ResourceDeletedError: a server entity the client is working with has been deleted.
* ResourceLockedError: the client attempted to work with a server entity to which it has no access because another client is working with it.
* SenderBusyError: the client sender does not have enough link credits to send the message.
* ServerBusyError: the server is busy. Callers should wait a while and retry the operation.
* ServiceCommunicationError: Error for signaling general communication errors related to messaging operations.
* ServiceUnavailableError: the service is unavailable. The operation should be retried.
* SessionCannotBeLockedError: the Azure ServiceBus session cannot be locked.
* SessionLockLostError: the lock on the Azure ServiceBus session is lost.
* SessionWindowViolationError: the peer violated incoming window for the session.
* StoreLockLostError: the store lock is lost.
* SystemError: a low level system error is thrown by node.js. See {@link https://nodejs.org/api/errors.html#errors_class_systemerror}.
* TransferLimitExceededError: the peer sent more message transfers than currently allowed on the link.
* UnattachedHandleError: currently in use of an attached link.
* UnauthorizedError: the connection parameters are wrong and the server refused the connection.
*/
export type MessagingErrorCodes =
// Error is thrown when the address is already in use.
| "AddressAlreadyInUseError"
// Error is thrown when an incorrect argument was received.
| "ArgumentError"
// Error is thrown when an argument has a value that is out of the admissible range.
| "ArgumentOutOfRangeError"
// Error is thrown when an operator intervened to close the connection for some reason.
| "ConnectionForcedError"
// Error is thrown when the container is no longer available on the current connection.
| "ConnectionRedirectError"
// Error is thrown when data could not be decoded.
| "DecodeError"
// Error is thrown when an operator intervened to detach for some reason.
| "DetachForcedError"
// Error is thrown when input was received for a link that was detached with an error.
| "ErrantLinkError"
// Error is thrown when the peer cannot send a frame because the smallest encoding of
// the performative with the currently valid values would be too large to fit within
// a frame of the agreed maximum frame size.
| "FrameSizeTooSmallError"
// Error is thrown when a valid frame header cannot be formed from the incoming byte stream.
| "FramingError"
// Error is thrown when an attach was received using a handle that is already in use for an attached link.
| "HandleInUseError"
// Error is thrown when the peer sent a frame that is not permitted in the current state.
| "IllegalStateError"
// Error is thrown when an internal server error occurred. You may have found a bug?
| "InternalServerError"
// Error is thrown when an invalid field was passed in a frame body, and the operation could not proceed.
| "InvalidFieldError"
// Error is thrown when an operation is attempted but is not allowed.
| "InvalidOperationError"
// Error is thrown when the address provided cannot be resolved to a terminus at the current container.
| "LinkRedirectError"
// Error is thrown when the lock on the message is lost.
| "MessageLockLostError"
// Error is thrown when message is not found.
| "MessageNotFoundError"
// Error is thrown when the message sent is too large: the maximum size is 256Kb.
| "MessageTooLargeError"
// Error is thrown when no new messages are received for the specified time.
| "MessageWaitTimeout"
// Error is thrown when an attempt is made to create an entity that already exists.
| "MessagingEntityAlreadyExistsError"
// Error is thrown when trying to access/connect to a disabled messaging entity.
| "MessagingEntityDisabledError"
// the messaging entity does not exist.
| "MessagingEntityNotFoundError"
// Error is thrown when a matching subscription is not found.
| "NoMatchingSubscriptionError"
// Error is thrown when a feature is not implemented yet but the placeholder is present.
| "NotImplementedError"
// Error is thrown when server cancels the operation due to an internal issue.
| "OperationCancelledError"
// the service fails to respond within a given timeframe.
| "OperationTimeoutError"
// Error is thrown when an attempt is made to access a partition that is not owned by the
// requesting entity.
| "PartitionNotOwnedError"
// Error is thrown when a condition that should have been met in order to execute an operation was not.
| "PreconditionFailedError"
// Error is thrown when access to publisher has been revoked.
| "PublisherRevokedError"
// Error is thrown the the Azure EventHub/ServiceBus quota has been exceeded.
// Quotas are reset periodically, this operation will have to wait until then.
// The messaging entity has reached its maximum allowable size.
// This can happen if the maximum number of receivers (which is 5) has already
// been opened on a per-consumer group level.
| "QuotaExceededError"
// Error is thrown when two or more instances connect to the same partition
// with different epoch values.
| "ReceiverDisconnectedError"
// Error is thrown when relay is not found.
| "RelayNotFoundError"
// Error is thrown when a server entity the client is working with has been deleted.
| "ResourceDeletedError"
// Error is thrown when the client attempted to work with a server entity to which it
// has no access because another client is working with it.
| "ResourceLockedError"
// Error is thrown when the client sender does not have enough link credits to send the message.
| "SenderBusyError"
// Error is thrown when the server is busy. Callers should wait a while and retry the operation.
| "ServerBusyError"
// Error for signaling general communication errors related to messaging operations.
| "ServiceCommunicationError"
// Error is thrown when the service is unavailable. The operation should be retried.
| "ServiceUnavailableError"
// Error is thrown when the Azure ServiceBus session cannot be locked.
| "SessionCannotBeLockedError"
// Error is thrown when the lock on the Azure ServiceBus session is lost.
| "SessionLockLostError"
// Error is thrown when the peer violated incoming window for the session.
| "SessionWindowViolationError"
// Error is thrown when the store lock is lost.
| "StoreLockLostError"
// Error is thrown when a low level system error is thrown by node.js.
// {@link https://nodejs.org/api/errors.html#errors_class_systemerror}
| "SystemError"
// Error is thrown when the peer sent more message transfers than currently allowed on the link.
| "TransferLimitExceededError"
// Error is thrown when a frame (other than attach) was received referencing a handle which is not
// currently in use of an attached link.
| "UnattachedHandleError"
// Error is thrown when the connection parameters are wrong and the server refused the connection.
| "UnauthorizedError";

/**
* Determines if an error is a MessagingError.
*
Expand All @@ -648,7 +492,7 @@ export class MessagingError extends Error {
/**
* A string label that identifies the error.
*/
code?: MessagingErrorCodes | string;
code?: string;
/**
* System-provided error number.
* Only present if the `MessagingError` was instantiated with a Node.js `SystemError`.
Expand Down
2 changes: 0 additions & 2 deletions sdk/core/core-amqp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ export {
} from "./ConnectionContextBase";
export {
MessagingError,
MessagingErrorCodes,
isMessagingError,
ErrorNameConditionMapper,
ConditionStatusMapper,
ConditionErrorNameMapper,
translate,
retryableErrors,
Expand Down
4 changes: 4 additions & 0 deletions sdk/servicebus/service-bus/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## 7.0.0 (Unreleased)

### Breaking changes

- The `ServiceBusError.reason` field has been renamed `ServiceBusError.code`.
The `code` field can be used to differentiate what caused a `ServiceBusError` to be thrown.
- Numbers passed in `applicationProperties` of the correlation rule filter and `sqlParameters` under SQLRuleFilter will now be serialized as "double"(used to be "int") while sending the requests. The "double" and "int" values in the response will now be deserialized as "number"("double" wasn't supported before).
[PR 12349](https://github.com/Azure/azure-sdk-for-js/pull/12349)

Expand Down
9 changes: 3 additions & 6 deletions sdk/servicebus/service-bus/review/service-bus.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { Delivery } from 'rhea-promise';
import { HttpResponse } from '@azure/core-http';
import Long from 'long';
import { MessagingError } from '@azure/core-amqp';
import { MessagingErrorCodes } from '@azure/core-amqp';
import { OperationOptions } from '@azure/core-http';
import { PagedAsyncIterableIterator } from '@azure/core-paging';
import { PageSettings } from '@azure/core-paging';
Expand Down Expand Up @@ -145,8 +144,6 @@ export interface MessageHandlers {

export { MessagingError }

export { MessagingErrorCodes }

// @public
export interface NamespaceProperties {
createdAt: Date;
Expand Down Expand Up @@ -305,11 +302,11 @@ export interface ServiceBusConnectionStringProperties {
// @public
export class ServiceBusError extends MessagingError {
constructor(messagingError: MessagingError);
reason: ServiceBusErrorReason;
}
code: ServiceBusErrorCode;
}

// @public
export type ServiceBusErrorReason =
export type ServiceBusErrorCode =
/**
* The exception was the result of a general error within the client library.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ async function receiveFromNextSession(serviceBusClient) {
} catch (err) {
if (
isServiceBusError(err) &&
(err.reason === "SessionCannotBeLocked" || err.reason === "ServiceTimeout")
(err.code === "SessionCannotBeLocked" || err.code === "ServiceTimeout")
) {
console.log(`INFO: no available sessions, sleeping for ${delayOnErrorMs}`);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ async function main() {

// the `subscribe() call will not stop trying to receive messages without explicit intervention from you.
if (isServiceBusError(args.error)) {
switch (args.error.reason) {
switch (args.error.code) {
case "MessagingEntityDisabled":
case "MessagingEntityNotFound":
case "Unauthorized":
// It's possible you have a temporary infrastructure change (for instance, the entity being
// temporarily disabled). The handler will continue to retry if `close()` is not called on the subscription - it is completely up to you
// what is considered fatal for your program.
console.log(
`An unrecoverable error occurred. Stopping processing. ${args.error.reason}`,
`An unrecoverable error occurred. Stopping processing. ${args.error.code}`,
args.error
);
await subscription.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async function receiveFromNextSession(serviceBusClient: ServiceBusClient): Promi
} catch (err) {
if (
isServiceBusError(err) &&
(err.reason === "SessionCannotBeLocked" || err.reason === "ServiceTimeout")
(err.code === "SessionCannotBeLocked" || err.code === "ServiceTimeout")
) {
console.log(`INFO: no available sessions, sleeping for ${delayOnErrorMs}`);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ export async function main() {

// the `subscribe() call will not stop trying to receive messages without explicit intervention from you.
if (isServiceBusError(args.error)) {
switch (args.error.reason) {
switch (args.error.code) {
case "MessagingEntityDisabled":
case "MessagingEntityNotFound":
case "Unauthorized":
// It's possible you have a temporary infrastructure change (for instance, the entity being
// temporarily disabled). The handler will continue to retry if `close()` is not called on the subscription - it is completely up to you
// what is considered fatal for your program.
console.log(
`An unrecoverable error occurred. Stopping processing. ${args.error.reason}`,
`An unrecoverable error occurred. Stopping processing. ${args.error.code}`,
args.error
);
await subscription.close();
Expand Down
Loading

0 comments on commit a5ba074

Please sign in to comment.