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

add FatalError #1231

Merged
merged 2 commits into from
Feb 13, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Any component based on runtime >= 0.14 will no longer work with loader <= 0.8
## New Error types
The following new error interfaces have been added:
- `IWriteError` is thrown when ops are sent on a read-only document
- `IFatalError` is thrown when a fatal error (500) is received from ODSP

## `IComponentContext` - `createSubComponent` removed, `createComponent` signature updated

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
IClient,
IConnect,
} from "@microsoft/fluid-protocol-definitions";
import { ThrottlingError } from "@microsoft/fluid-driver-utils";
import { FatalError, ThrottlingError } from "@microsoft/fluid-driver-utils";
import { IOdspSocketError } from "./contracts";
import { debug } from "./debug";
import { errorObjectFromOdspError, OdspNetworkError, socketErrorRetryFilter } from "./odspUtils";
Expand Down Expand Up @@ -106,7 +106,7 @@ export class OdspDocumentDeltaConnection extends DocumentDeltaConnection impleme
if (errorObject !== null && typeof errorObject === "object" && errorObject.canRetry) {
const socketError: IOdspSocketError = errorObject.socketError;
if (typeof socketError === "object" && socketError !== null) {
throw errorObjectFromOdspError(socketError, socketErrorRetryFilter(socketError.code));
throw errorObjectFromOdspError(socketError, socketErrorRetryFilter);
}
}
throw errorObject;
Expand Down Expand Up @@ -174,7 +174,7 @@ export class OdspDocumentDeltaConnection extends DocumentDeltaConnection impleme
// filter out retryable vs. non-retryable cases.
// Specifically, it will have one retry for 403 - see
// connectToDeltaStream() / getWithRetryForTokenRefresh() call.
const error = errorObjectFromOdspError(socketError, true /*canRetry */);
const error = errorObjectFromOdspError(socketError);

// The server always closes the socket after sending this message
// fully remove the socket reference now
Expand All @@ -200,7 +200,7 @@ export class OdspDocumentDeltaConnection extends DocumentDeltaConnection impleme
private static removeSocketIoReference(
key: string,
isFatalError: boolean,
reason: string | OdspNetworkError | ThrottlingError) {
reason: string | OdspNetworkError | ThrottlingError | FatalError) {
const socketReference = OdspDocumentDeltaConnection.socketIoSockets.get(key);
if (!socketReference) {
// This is expected to happen if we removed the reference due the socket not being connected
Expand Down
10 changes: 6 additions & 4 deletions packages/drivers/odsp-socket-storage/src/odspUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License.
*/

import { isOnline, NetworkError, ThrottlingError, OnlineStatus } from "@microsoft/fluid-driver-utils";
import { isOnline, FatalError, NetworkError, ThrottlingError, OnlineStatus } from "@microsoft/fluid-driver-utils";
import { default as fetch, RequestInfo as FetchRequestInfo, RequestInit as FetchRequestInit } from "node-fetch";
import * as sha from "sha.js";
import { IOdspSocketError } from "./contracts";
Expand Down Expand Up @@ -45,14 +45,16 @@ export class OdspNetworkError extends NetworkError {
/**
* Returns network error based on error object from ODSP socket (IOdspSocketError)
*/
export function errorObjectFromOdspError(socketError: IOdspSocketError, canRetry: boolean) {
if (socketError.retryAfter) {
export function errorObjectFromOdspError(socketError: IOdspSocketError, retryFilter?: RetryFilter) {
if (socketError.code === 500) {
return new FatalError(socketError.message);
} else if (socketError.retryAfter) {
return new ThrottlingError(socketError.message, socketError.retryAfter);
} else {
return new OdspNetworkError(
socketError.message,
socketError.code,
canRetry,
retryFilter?.(socketError.code) ?? true,
);
}
}
Expand Down
9 changes: 8 additions & 1 deletion packages/loader/driver-definitions/src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

// tslint:disable: no-unsafe-any
export enum ErrorType {
generalError,
Expand All @@ -10,10 +11,11 @@ export enum ErrorType {
serviceError,
summarizingError,
writeError,
fatalError,
}

export type IError = IGeneralError | IThrottlingError | IConnectionError |
IServiceError | ISummarizingError | IWriteError;
IServiceError | ISummarizingError | IWriteError | IFatalError;

export interface IGeneralError {
readonly errorType: ErrorType.generalError;
Expand Down Expand Up @@ -51,3 +53,8 @@ export interface IWriteError {
readonly errorType: ErrorType.writeError;
readonly critical: boolean;
}

export interface IFatalError {
readonly errorType: ErrorType.fatalError;
readonly critical: boolean;
}
23 changes: 22 additions & 1 deletion packages/loader/driver-utils/src/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { IConnectionError, IThrottlingError, IWriteError, ErrorType } from "@microsoft/fluid-driver-definitions";

import {
IConnectionError,
IFatalError,
IThrottlingError,
IWriteError,
ErrorType,
} from "@microsoft/fluid-driver-definitions";

/**
* Network error error class - used to communicate all network errors
*/
export class NetworkError extends Error implements IConnectionError {
readonly errorType: ErrorType.connectionError = ErrorType.connectionError;

constructor(
errorMessage: string,
readonly statusCode?: number,
Expand Down Expand Up @@ -52,6 +60,19 @@ export class WriteError extends Error implements IWriteError {
}
}

export class FatalError extends Error implements IFatalError {
readonly errorType: ErrorType.fatalError = ErrorType.fatalError;
public readonly critical = true;

constructor(errorMessage: string) {
super(errorMessage);
}

public getCustomProperties() {
return copyObjectProps(this);
}
}

export function copyObjectProps(obj: object) {
const prop = {};
// Could not use {...obj} because it does not return properties of base class.
Expand Down
6 changes: 3 additions & 3 deletions packages/test/end-to-end/src/test/error.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe("Errors Types", () => {
message: "Test Error",
code: 400,
};
const networkError = createIError(errorObjectFromOdspError(err, false));
const networkError = createIError(errorObjectFromOdspError(err, () => false));
assert.equal(networkError.errorType, ErrorType.connectionError, "Error is not a network error");
});

Expand All @@ -104,7 +104,7 @@ describe("Errors Types", () => {
code: 529,
retryAfter: 100,
};
const throttlingError = createIError(errorObjectFromOdspError(err, true));
const throttlingError = createIError(errorObjectFromOdspError(err, () => true));
assert.equal(throttlingError.errorType, ErrorType.throttlingError, "Error is not a throttling error");
});

Expand All @@ -114,7 +114,7 @@ describe("Errors Types", () => {
code: 529,
retryAfter: 100,
};
const error1 = createIError(errorObjectFromOdspError(err, true), true);
const error1 = createIError(errorObjectFromOdspError(err, () => true), true);
const error2 = createIError(error1, false);
assert.equal(error1, error2, "Both errors should be same!!");
});
Expand Down