@fluidframework/container-loader 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191258
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +131 -0
- package/README.md +10 -6
- package/dist/audience.d.ts +1 -0
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js +5 -3
- package/dist/audience.js.map +1 -1
- package/dist/catchUpMonitor.js +2 -2
- package/dist/catchUpMonitor.js.map +1 -1
- package/dist/connectionManager.d.ts +5 -5
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +97 -93
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +15 -14
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +50 -52
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +20 -9
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +327 -277
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +2 -7
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +2 -14
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +12 -13
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +21 -8
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +3 -3
- package/dist/contracts.js.map +1 -1
- package/dist/debugLogger.d.ts +30 -0
- package/dist/debugLogger.d.ts.map +1 -0
- package/dist/debugLogger.js +95 -0
- package/dist/debugLogger.js.map +1 -0
- package/dist/deltaManager.d.ts +21 -10
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +114 -66
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts +1 -1
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +10 -10
- package/dist/deltaQueue.js.map +1 -1
- package/dist/disposal.d.ts +2 -2
- package/dist/disposal.d.ts.map +1 -1
- package/dist/disposal.js +1 -1
- package/dist/disposal.js.map +1 -1
- package/dist/error.d.ts +23 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +32 -0
- package/dist/error.js.map +1 -0
- package/dist/loader.d.ts +22 -3
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +82 -51
- package/dist/loader.js.map +1 -1
- package/dist/noopHeuristic.d.ts +2 -2
- package/dist/noopHeuristic.d.ts.map +1 -1
- package/dist/noopHeuristic.js +6 -5
- package/dist/noopHeuristic.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts +4 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +25 -4
- package/dist/protocol.js.map +1 -1
- package/dist/quorum.d.ts +4 -1
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js +1 -13
- package/dist/quorum.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js +4 -4
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/utils.d.ts +8 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +30 -11
- package/dist/utils.js.map +1 -1
- package/lib/audience.d.ts +1 -0
- package/lib/audience.d.ts.map +1 -1
- package/lib/audience.js +4 -2
- package/lib/audience.js.map +1 -1
- package/lib/catchUpMonitor.js +1 -1
- package/lib/catchUpMonitor.js.map +1 -1
- package/lib/connectionManager.d.ts +5 -5
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +74 -67
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +15 -14
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +27 -29
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +20 -9
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +288 -238
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +2 -7
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +2 -14
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +5 -6
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +21 -8
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js +3 -3
- package/lib/contracts.js.map +1 -1
- package/lib/debugLogger.d.ts +30 -0
- package/lib/debugLogger.d.ts.map +1 -0
- package/lib/debugLogger.js +91 -0
- package/lib/debugLogger.js.map +1 -0
- package/lib/deltaManager.d.ts +21 -10
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +88 -37
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts +1 -1
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +3 -3
- package/lib/deltaQueue.js.map +1 -1
- package/lib/disposal.d.ts +2 -2
- package/lib/disposal.d.ts.map +1 -1
- package/lib/disposal.js +1 -1
- package/lib/disposal.js.map +1 -1
- package/lib/error.d.ts +23 -0
- package/lib/error.d.ts.map +1 -0
- package/lib/error.js +28 -0
- package/lib/error.js.map +1 -0
- package/lib/loader.d.ts +22 -3
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +82 -51
- package/lib/loader.js.map +1 -1
- package/lib/noopHeuristic.d.ts +2 -2
- package/lib/noopHeuristic.d.ts.map +1 -1
- package/lib/noopHeuristic.js +2 -1
- package/lib/noopHeuristic.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts +4 -2
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +25 -4
- package/lib/protocol.js.map +1 -1
- package/lib/quorum.d.ts +4 -1
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js +0 -11
- package/lib/quorum.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js +2 -2
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts +8 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +25 -7
- package/lib/utils.js.map +1 -1
- package/package.json +26 -32
- package/src/audience.ts +7 -1
- package/src/catchUpMonitor.ts +1 -1
- package/src/connectionManager.ts +75 -51
- package/src/connectionStateHandler.ts +31 -38
- package/src/container.ts +335 -240
- package/src/containerContext.ts +0 -16
- package/src/containerStorageAdapter.ts +2 -1
- package/src/contracts.ts +27 -11
- package/src/debugLogger.ts +113 -0
- package/src/deltaManager.ts +84 -34
- package/src/deltaQueue.ts +2 -1
- package/src/disposal.ts +2 -2
- package/src/error.ts +44 -0
- package/src/loader.ts +83 -35
- package/src/noopHeuristic.ts +3 -2
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +33 -2
- package/src/quorum.ts +0 -10
- package/src/retriableDocumentStorageService.ts +2 -4
- package/src/utils.ts +33 -8
package/src/containerContext.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
import { FluidObject } from "@fluidframework/core-interfaces";
|
|
19
19
|
import { IDocumentStorageService } from "@fluidframework/driver-definitions";
|
|
20
20
|
import {
|
|
21
|
-
IClientConfiguration,
|
|
22
21
|
IClientDetails,
|
|
23
22
|
IDocumentMessage,
|
|
24
23
|
IQuorumClients,
|
|
@@ -61,16 +60,6 @@ export class ContainerContext implements IContainerContext {
|
|
|
61
60
|
return this._getConnected();
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
public get serviceConfiguration(): IClientConfiguration | undefined {
|
|
65
|
-
return this._getServiceConfiguration();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private _disposed = false;
|
|
69
|
-
|
|
70
|
-
public get disposed() {
|
|
71
|
-
return this._disposed;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
63
|
constructor(
|
|
75
64
|
public readonly options: ILoaderOptions,
|
|
76
65
|
public readonly scope: FluidObject,
|
|
@@ -103,7 +92,6 @@ export class ContainerContext implements IContainerContext {
|
|
|
103
92
|
public readonly getAbsoluteUrl: (relativeUrl: string) => Promise<string | undefined>,
|
|
104
93
|
private readonly _getContainerDiagnosticId: () => string | undefined,
|
|
105
94
|
private readonly _getClientId: () => string | undefined,
|
|
106
|
-
private readonly _getServiceConfiguration: () => IClientConfiguration | undefined,
|
|
107
95
|
private readonly _getAttachState: () => AttachState,
|
|
108
96
|
private readonly _getConnected: () => boolean,
|
|
109
97
|
public readonly getSpecifiedCodeDetails: () => IFluidCodeDetails | undefined,
|
|
@@ -113,10 +101,6 @@ export class ContainerContext implements IContainerContext {
|
|
|
113
101
|
public readonly pendingLocalState?: unknown,
|
|
114
102
|
) {}
|
|
115
103
|
|
|
116
|
-
public dispose(error?: Error): void {
|
|
117
|
-
this._disposed = true;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
104
|
public getLoadedFromVersion(): IVersion | undefined {
|
|
121
105
|
return this._version;
|
|
122
106
|
}
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { IDisposable } from "@fluidframework/core-interfaces";
|
|
7
7
|
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
8
|
-
import {
|
|
8
|
+
import { bufferToString, stringToBuffer } from "@fluid-internal/client-utils";
|
|
9
|
+
import { assert } from "@fluidframework/core-utils";
|
|
9
10
|
import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
|
|
10
11
|
import {
|
|
11
12
|
FetchSource,
|
package/src/contracts.ts
CHANGED
|
@@ -3,24 +3,25 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { ITelemetryProperties } from "@fluidframework/core-interfaces";
|
|
6
|
+
import { IErrorBase, ITelemetryProperties } from "@fluidframework/core-interfaces";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
ReadOnlyInfo,
|
|
10
|
-
IConnectionDetailsInternal,
|
|
8
|
+
IConnectionDetails,
|
|
11
9
|
ICriticalContainerError,
|
|
10
|
+
IDeltaQueue,
|
|
12
11
|
IFluidCodeDetails,
|
|
13
12
|
isFluidPackage,
|
|
13
|
+
ReadOnlyInfo,
|
|
14
14
|
} from "@fluidframework/container-definitions";
|
|
15
15
|
import {
|
|
16
16
|
ConnectionMode,
|
|
17
|
-
IDocumentMessage,
|
|
18
|
-
ISequencedDocumentMessage,
|
|
19
17
|
IClientConfiguration,
|
|
20
18
|
IClientDetails,
|
|
19
|
+
IDocumentMessage,
|
|
20
|
+
ISequencedDocumentMessage,
|
|
21
|
+
ISignalClient,
|
|
21
22
|
ISignalMessage,
|
|
22
23
|
} from "@fluidframework/protocol-definitions";
|
|
23
|
-
import {
|
|
24
|
+
import { IContainerPackageInfo } from "@fluidframework/driver-definitions";
|
|
24
25
|
|
|
25
26
|
export enum ReconnectMode {
|
|
26
27
|
Never = "Never",
|
|
@@ -28,6 +29,21 @@ export enum ReconnectMode {
|
|
|
28
29
|
Enabled = "Enabled",
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
export interface IConnectionStateChangeReason<T extends IErrorBase = IErrorBase> {
|
|
33
|
+
text: string;
|
|
34
|
+
error?: T;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Internal version of IConnectionDetails with props are only exposed internally
|
|
39
|
+
*/
|
|
40
|
+
export interface IConnectionDetailsInternal extends IConnectionDetails {
|
|
41
|
+
mode: ConnectionMode;
|
|
42
|
+
version: string;
|
|
43
|
+
initialClients: ISignalClient[];
|
|
44
|
+
reason: IConnectionStateChangeReason;
|
|
45
|
+
}
|
|
46
|
+
|
|
31
47
|
/**
|
|
32
48
|
* Connection manager (implements this interface) is responsible for maintaining connection
|
|
33
49
|
* to relay service.
|
|
@@ -95,7 +111,7 @@ export interface IConnectionManager {
|
|
|
95
111
|
/**
|
|
96
112
|
* Initiates connection to relay service (noop if already connected).
|
|
97
113
|
*/
|
|
98
|
-
connect(reason:
|
|
114
|
+
connect(reason: IConnectionStateChangeReason, connectionMode?: ConnectionMode): void;
|
|
99
115
|
|
|
100
116
|
/**
|
|
101
117
|
* Disposed connection manager
|
|
@@ -139,7 +155,7 @@ export interface IConnectionManagerFactoryArgs {
|
|
|
139
155
|
/**
|
|
140
156
|
* Called whenever connection to relay service is lost.
|
|
141
157
|
*/
|
|
142
|
-
readonly disconnectHandler: (reason:
|
|
158
|
+
readonly disconnectHandler: (reason: IConnectionStateChangeReason) => void;
|
|
143
159
|
|
|
144
160
|
/**
|
|
145
161
|
* Called whenever new connection to rely service is established
|
|
@@ -169,12 +185,12 @@ export interface IConnectionManagerFactoryArgs {
|
|
|
169
185
|
/**
|
|
170
186
|
* Called whenever we try to start establishing a new connection.
|
|
171
187
|
*/
|
|
172
|
-
readonly establishConnectionHandler: (reason:
|
|
188
|
+
readonly establishConnectionHandler: (reason: IConnectionStateChangeReason) => void;
|
|
173
189
|
|
|
174
190
|
/**
|
|
175
191
|
* Called whenever we cancel the connection in progress.
|
|
176
192
|
*/
|
|
177
|
-
readonly cancelConnectionHandler: (reason:
|
|
193
|
+
readonly cancelConnectionHandler: (reason: IConnectionStateChangeReason) => void;
|
|
178
194
|
}
|
|
179
195
|
|
|
180
196
|
/**
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ITelemetryBaseEvent,
|
|
8
|
+
ITelemetryBaseLogger,
|
|
9
|
+
ITelemetryProperties,
|
|
10
|
+
} from "@fluidframework/core-interfaces";
|
|
11
|
+
import { performance } from "@fluid-internal/client-utils";
|
|
12
|
+
import { debug as registerDebug, IDebugger } from "debug";
|
|
13
|
+
import {
|
|
14
|
+
ITelemetryLoggerExt,
|
|
15
|
+
ITelemetryLoggerPropertyBags,
|
|
16
|
+
createMultiSinkLogger,
|
|
17
|
+
eventNamespaceSeparator,
|
|
18
|
+
formatTick,
|
|
19
|
+
} from "@fluidframework/telemetry-utils";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Implementation of debug logger
|
|
23
|
+
*/
|
|
24
|
+
export class DebugLogger implements ITelemetryBaseLogger {
|
|
25
|
+
/**
|
|
26
|
+
* Mix in debug logger with another logger.
|
|
27
|
+
* Returned logger will output events to both newly created debug logger, as well as base logger
|
|
28
|
+
* @param namespace - Telemetry event name prefix to add to all events
|
|
29
|
+
* @param properties - Base properties to add to all events
|
|
30
|
+
* @param propertyGetters - Getters to add additional properties to all events
|
|
31
|
+
* @param baseLogger - Base logger to output events (in addition to debug logger being created). Can be undefined.
|
|
32
|
+
*/
|
|
33
|
+
public static mixinDebugLogger(
|
|
34
|
+
namespace: string,
|
|
35
|
+
baseLogger?: ITelemetryBaseLogger,
|
|
36
|
+
properties?: ITelemetryLoggerPropertyBags,
|
|
37
|
+
): ITelemetryLoggerExt {
|
|
38
|
+
// Setup base logger upfront, such that host can disable it (if needed)
|
|
39
|
+
const debug = registerDebug(namespace);
|
|
40
|
+
|
|
41
|
+
// Create one for errors that is always enabled
|
|
42
|
+
// It can be silenced by replacing console.error if the debug namespace is not enabled.
|
|
43
|
+
const debugErr = registerDebug(namespace);
|
|
44
|
+
debugErr.log = function (...args) {
|
|
45
|
+
if (debug.enabled === true) {
|
|
46
|
+
// if the namespace is enabled, just use the default logger
|
|
47
|
+
registerDebug.log(...args);
|
|
48
|
+
} else {
|
|
49
|
+
// other wise, use the console logger (which could be replaced and silenced)
|
|
50
|
+
console.error(...args);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
debugErr.enabled = true;
|
|
54
|
+
|
|
55
|
+
return createMultiSinkLogger({
|
|
56
|
+
namespace,
|
|
57
|
+
loggers: [baseLogger, new DebugLogger(debug, debugErr)],
|
|
58
|
+
properties,
|
|
59
|
+
tryInheritProperties: true,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private constructor(private readonly debug: IDebugger, private readonly debugErr: IDebugger) {}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Send an event to debug loggers
|
|
67
|
+
*
|
|
68
|
+
* @param event - the event to send
|
|
69
|
+
*/
|
|
70
|
+
public send(event: ITelemetryBaseEvent): void {
|
|
71
|
+
const newEvent: ITelemetryProperties = { ...event };
|
|
72
|
+
const isError = newEvent.category === "error";
|
|
73
|
+
let logger = isError ? this.debugErr : this.debug;
|
|
74
|
+
|
|
75
|
+
// Use debug's coloring schema for base of the event
|
|
76
|
+
const index = event.eventName.lastIndexOf(eventNamespaceSeparator);
|
|
77
|
+
const name = event.eventName.substring(index + 1);
|
|
78
|
+
if (index > 0) {
|
|
79
|
+
logger = logger.extend(event.eventName.substring(0, index));
|
|
80
|
+
}
|
|
81
|
+
newEvent.eventName = undefined;
|
|
82
|
+
|
|
83
|
+
let tick = "";
|
|
84
|
+
tick = `tick=${formatTick(performance.now())}`;
|
|
85
|
+
|
|
86
|
+
// Extract stack to put it last, but also to avoid escaping '\n' in it by JSON.stringify below
|
|
87
|
+
const stack = newEvent.stack ?? "";
|
|
88
|
+
newEvent.stack = undefined;
|
|
89
|
+
|
|
90
|
+
// Watch out for circular references - they can come from two sources
|
|
91
|
+
// 1) error object - we do not control it and should remove it and retry
|
|
92
|
+
// 2) properties supplied by telemetry caller - that's a bug that should be addressed!
|
|
93
|
+
let payload: string;
|
|
94
|
+
try {
|
|
95
|
+
payload = JSON.stringify(newEvent);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
newEvent.error = undefined;
|
|
98
|
+
payload = JSON.stringify(newEvent);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (payload === "{}") {
|
|
102
|
+
payload = "";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Force errors out, to help with diagnostics
|
|
106
|
+
if (isError) {
|
|
107
|
+
logger.enabled = true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Print multi-line.
|
|
111
|
+
logger(`${name} ${payload} ${tick} ${stack}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
package/src/deltaManager.ts
CHANGED
|
@@ -3,32 +3,36 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { default as AbortController } from "abort-controller";
|
|
7
6
|
import { v4 as uuid } from "uuid";
|
|
8
|
-
import { IEventProvider } from "@fluidframework/common-definitions";
|
|
9
|
-
import { ITelemetryProperties, ITelemetryErrorEvent } from "@fluidframework/core-interfaces";
|
|
10
7
|
import {
|
|
11
|
-
|
|
8
|
+
IThrottlingWarning,
|
|
9
|
+
IEventProvider,
|
|
10
|
+
ITelemetryProperties,
|
|
11
|
+
ITelemetryErrorEvent,
|
|
12
|
+
} from "@fluidframework/core-interfaces";
|
|
13
|
+
import {
|
|
14
|
+
ICriticalContainerError,
|
|
12
15
|
IDeltaManager,
|
|
13
16
|
IDeltaManagerEvents,
|
|
14
17
|
IDeltaQueue,
|
|
15
|
-
ICriticalContainerError,
|
|
16
|
-
IThrottlingWarning,
|
|
17
|
-
IConnectionDetailsInternal,
|
|
18
18
|
} from "@fluidframework/container-definitions";
|
|
19
|
-
import {
|
|
19
|
+
import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
20
|
+
import { assert } from "@fluidframework/core-utils";
|
|
20
21
|
import {
|
|
22
|
+
DataProcessingError,
|
|
23
|
+
extractSafePropertiesFromMessage,
|
|
21
24
|
normalizeError,
|
|
22
25
|
logIfFalse,
|
|
23
26
|
safeRaiseEvent,
|
|
24
27
|
isFluidError,
|
|
25
28
|
ITelemetryLoggerExt,
|
|
29
|
+
DataCorruptionError,
|
|
30
|
+
UsageError,
|
|
26
31
|
} from "@fluidframework/telemetry-utils";
|
|
27
32
|
import {
|
|
28
33
|
IDocumentDeltaStorageService,
|
|
29
34
|
IDocumentService,
|
|
30
|
-
|
|
31
|
-
IAnyDriverError,
|
|
35
|
+
DriverErrorTypes,
|
|
32
36
|
} from "@fluidframework/driver-definitions";
|
|
33
37
|
import {
|
|
34
38
|
IDocumentMessage,
|
|
@@ -38,21 +42,21 @@ import {
|
|
|
38
42
|
ConnectionMode,
|
|
39
43
|
} from "@fluidframework/protocol-definitions";
|
|
40
44
|
import { NonRetryableError, isRuntimeMessage, MessageType2 } from "@fluidframework/driver-utils";
|
|
45
|
+
|
|
41
46
|
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} from "@fluidframework/container-utils";
|
|
48
|
-
import { IConnectionManagerFactoryArgs, IConnectionManager } from "./contracts";
|
|
47
|
+
IConnectionDetailsInternal,
|
|
48
|
+
IConnectionManager,
|
|
49
|
+
IConnectionManagerFactoryArgs,
|
|
50
|
+
IConnectionStateChangeReason,
|
|
51
|
+
} from "./contracts";
|
|
49
52
|
import { DeltaQueue } from "./deltaQueue";
|
|
50
53
|
import { OnlyValidTermValue } from "./protocol";
|
|
54
|
+
import { ThrottlingWarning } from "./error";
|
|
51
55
|
|
|
52
56
|
export interface IConnectionArgs {
|
|
53
57
|
mode?: ConnectionMode;
|
|
54
58
|
fetchOpsFromStorage?: boolean;
|
|
55
|
-
reason:
|
|
59
|
+
reason: IConnectionStateChangeReason;
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
/**
|
|
@@ -63,8 +67,11 @@ export interface IDeltaManagerInternalEvents extends IDeltaManagerEvents {
|
|
|
63
67
|
(event: "throttled", listener: (error: IThrottlingWarning) => void);
|
|
64
68
|
(event: "closed" | "disposed", listener: (error?: ICriticalContainerError) => void);
|
|
65
69
|
(event: "connect", listener: (details: IConnectionDetailsInternal, opsBehind?: number) => void);
|
|
66
|
-
(event: "establishingConnection", listener: (reason:
|
|
67
|
-
(
|
|
70
|
+
(event: "establishingConnection", listener: (reason: IConnectionStateChangeReason) => void);
|
|
71
|
+
(
|
|
72
|
+
event: "cancelEstablishingConnection",
|
|
73
|
+
listener: (reason: IConnectionStateChangeReason) => void,
|
|
74
|
+
);
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
/**
|
|
@@ -74,6 +81,21 @@ interface IBatchMetadata {
|
|
|
74
81
|
batch?: boolean;
|
|
75
82
|
}
|
|
76
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Interface used to define a strategy for handling incoming delta messages
|
|
86
|
+
*/
|
|
87
|
+
export interface IDeltaHandlerStrategy {
|
|
88
|
+
/**
|
|
89
|
+
* Processes the message.
|
|
90
|
+
*/
|
|
91
|
+
process: (message: ISequencedDocumentMessage) => void;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Processes the signal.
|
|
95
|
+
*/
|
|
96
|
+
processSignal: (message: ISignalMessage) => void;
|
|
97
|
+
}
|
|
98
|
+
|
|
77
99
|
/**
|
|
78
100
|
* Determines if message was sent by client, not service
|
|
79
101
|
*/
|
|
@@ -93,6 +115,17 @@ function isClientMessage(message: ISequencedDocumentMessage | IDocumentMessage):
|
|
|
93
115
|
}
|
|
94
116
|
}
|
|
95
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Type is used to cast AbortController to represent new version of DOM API and prevent build issues
|
|
120
|
+
* TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
121
|
+
*/
|
|
122
|
+
type AbortControllerReal = AbortController & { abort(reason?: any): void };
|
|
123
|
+
/**
|
|
124
|
+
* Type is used to cast AbortSignal to represent new version of DOM API and prevent build issues
|
|
125
|
+
* TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
126
|
+
*/
|
|
127
|
+
type AbortSignalReal = AbortSignal & { reason: any };
|
|
128
|
+
|
|
96
129
|
/**
|
|
97
130
|
* Manages the flow of both inbound and outbound messages. This class ensures that shared objects receive delta
|
|
98
131
|
* messages in order regardless of possible network conditions or timings causing out of order delivery.
|
|
@@ -320,6 +353,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
320
353
|
return {
|
|
321
354
|
sequenceNumber: this.lastSequenceNumber,
|
|
322
355
|
opsSize: this.opsSize > 0 ? this.opsSize : undefined,
|
|
356
|
+
deltaManagerState: this._disposed ? "disposed" : this._closed ? "closed" : "open",
|
|
323
357
|
...this.connectionManager.connectionProps,
|
|
324
358
|
};
|
|
325
359
|
}
|
|
@@ -373,15 +407,17 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
373
407
|
reconnectionDelayHandler: (delayMs: number, error: unknown) =>
|
|
374
408
|
this.emitDelayInfo(this.deltaStreamDelayId, delayMs, error),
|
|
375
409
|
closeHandler: (error: any) => this.close(error),
|
|
376
|
-
disconnectHandler: (reason:
|
|
377
|
-
this.disconnectHandler(reason
|
|
410
|
+
disconnectHandler: (reason: IConnectionStateChangeReason) =>
|
|
411
|
+
this.disconnectHandler(reason),
|
|
378
412
|
connectHandler: (connection: IConnectionDetailsInternal) =>
|
|
379
413
|
this.connectHandler(connection),
|
|
380
414
|
pongHandler: (latency: number) => this.emit("pong", latency),
|
|
381
415
|
readonlyChangeHandler: (readonly?: boolean) =>
|
|
382
416
|
safeRaiseEvent(this, this.logger, "readonly", readonly),
|
|
383
|
-
establishConnectionHandler: (reason:
|
|
384
|
-
|
|
417
|
+
establishConnectionHandler: (reason: IConnectionStateChangeReason) =>
|
|
418
|
+
this.establishingConnection(reason),
|
|
419
|
+
cancelConnectionHandler: (reason: IConnectionStateChangeReason) =>
|
|
420
|
+
this.cancelEstablishingConnection(reason),
|
|
385
421
|
};
|
|
386
422
|
|
|
387
423
|
this.connectionManager = createConnectionManager(props);
|
|
@@ -421,11 +457,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
421
457
|
// - inbound & inboundSignal are resumed in attachOpHandler() when we have handler setup
|
|
422
458
|
}
|
|
423
459
|
|
|
424
|
-
private cancelEstablishingConnection(reason:
|
|
460
|
+
private cancelEstablishingConnection(reason: IConnectionStateChangeReason) {
|
|
425
461
|
this.emit("cancelEstablishingConnection", reason);
|
|
426
462
|
}
|
|
427
463
|
|
|
428
|
-
private establishingConnection(reason:
|
|
464
|
+
private establishingConnection(reason: IConnectionStateChangeReason) {
|
|
429
465
|
this.emit("establishingConnection", reason);
|
|
430
466
|
}
|
|
431
467
|
|
|
@@ -485,7 +521,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
485
521
|
minSequenceNumber: number,
|
|
486
522
|
sequenceNumber: number,
|
|
487
523
|
handler: IDeltaHandlerStrategy,
|
|
488
|
-
prefetchType: "cached" | "all" | "none" = "none",
|
|
524
|
+
prefetchType: "sequenceNumber" | "cached" | "all" | "none" = "none",
|
|
489
525
|
) {
|
|
490
526
|
this.initSequenceNumber = sequenceNumber;
|
|
491
527
|
this.lastProcessedSequenceNumber = sequenceNumber;
|
|
@@ -559,7 +595,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
559
595
|
// on the wire, we might be always behind.
|
|
560
596
|
// See comment at the end of "connect" handler
|
|
561
597
|
if (fetchOpsFromStorage) {
|
|
562
|
-
this.fetchMissingDeltas(args.reason);
|
|
598
|
+
this.fetchMissingDeltas(args.reason.text);
|
|
563
599
|
}
|
|
564
600
|
|
|
565
601
|
this.connectionManager.connect(args.reason, args.mode);
|
|
@@ -624,7 +660,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
624
660
|
// This is useless for known ranges (to is defined) as it means request is over either way.
|
|
625
661
|
// And it will cancel unbound request too early, not allowing us to learn where the end of the file is.
|
|
626
662
|
if (!opsFromFetch && cancelFetch(op)) {
|
|
627
|
-
|
|
663
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
664
|
+
(controller as AbortControllerReal).abort("DeltaManager getDeltas fetch cancelled");
|
|
628
665
|
this._inbound.off("push", opListener);
|
|
629
666
|
}
|
|
630
667
|
};
|
|
@@ -632,7 +669,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
632
669
|
try {
|
|
633
670
|
this._inbound.on("push", opListener);
|
|
634
671
|
assert(this.closeAbortController.signal.onabort === null, 0x1e8 /* "reentrancy" */);
|
|
635
|
-
this.closeAbortController.signal.onabort = () =>
|
|
672
|
+
this.closeAbortController.signal.onabort = () =>
|
|
673
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
674
|
+
(controller as AbortControllerReal).abort(
|
|
675
|
+
(this.closeAbortController.signal as AbortSignalReal).reason,
|
|
676
|
+
);
|
|
636
677
|
|
|
637
678
|
const stream = this.deltaStorage.fetchMessages(
|
|
638
679
|
from, // inclusive
|
|
@@ -656,6 +697,14 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
656
697
|
}
|
|
657
698
|
}
|
|
658
699
|
} finally {
|
|
700
|
+
if (controller.signal.aborted) {
|
|
701
|
+
this.logger.sendTelemetryEvent({
|
|
702
|
+
eventName: "DeltaManager_GetDeltasAborted",
|
|
703
|
+
fetchReason,
|
|
704
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
705
|
+
reason: (controller.signal as AbortSignalReal).reason,
|
|
706
|
+
});
|
|
707
|
+
}
|
|
659
708
|
this.closeAbortController.signal.onabort = null;
|
|
660
709
|
this._inbound.off("push", opListener);
|
|
661
710
|
assert(!opsFromFetch, 0x289 /* "logic error" */);
|
|
@@ -710,7 +759,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
710
759
|
}
|
|
711
760
|
|
|
712
761
|
private clearQueues() {
|
|
713
|
-
|
|
762
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
763
|
+
(this.closeAbortController as AbortControllerReal).abort("DeltaManager is closed");
|
|
714
764
|
|
|
715
765
|
this._inbound.clear();
|
|
716
766
|
this._inboundSignal.clear();
|
|
@@ -731,9 +781,9 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
731
781
|
}
|
|
732
782
|
}
|
|
733
783
|
|
|
734
|
-
private disconnectHandler(reason:
|
|
784
|
+
private disconnectHandler(reason: IConnectionStateChangeReason) {
|
|
735
785
|
this.messageBuffer.length = 0;
|
|
736
|
-
this.emit("disconnect", reason
|
|
786
|
+
this.emit("disconnect", reason);
|
|
737
787
|
}
|
|
738
788
|
|
|
739
789
|
/**
|
|
@@ -893,7 +943,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
893
943
|
// pre-0.58 error message: twoMessagesWithSameSeqNumAndDifferentPayload
|
|
894
944
|
"Found two messages with the same sequenceNumber but different payloads. Likely to be a " +
|
|
895
945
|
"service issue",
|
|
896
|
-
|
|
946
|
+
DriverErrorTypes.fileOverwrittenInStorage,
|
|
897
947
|
{
|
|
898
948
|
clientId: this.connectionManager.clientId,
|
|
899
949
|
sequenceNumber: message.sequenceNumber,
|
package/src/deltaQueue.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IDeltaQueue, IDeltaQueueEvents } from "@fluidframework/container-definitions";
|
|
7
|
-
import { assert
|
|
7
|
+
import { assert } from "@fluidframework/core-utils";
|
|
8
|
+
import { performance, TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
8
9
|
import Deque from "double-ended-queue";
|
|
9
10
|
|
|
10
11
|
export interface IDeltaQueueWriter<T> {
|
package/src/disposal.ts
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { IDisposable } from "@fluidframework/
|
|
6
|
+
import { IDisposable } from "@fluidframework/core-interfaces";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Returns a wrapper around the provided function, which will only invoke the inner function if the provided
|
|
10
|
-
* {@link @fluidframework/
|
|
10
|
+
* {@link @fluidframework/core-interfaces#IDisposable | disposable} object has not yet been disposed.
|
|
11
11
|
*
|
|
12
12
|
* @throws Will throw an error if the item has already been disposed.
|
|
13
13
|
*/
|
package/src/error.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ITelemetryProperties, IThrottlingWarning } from "@fluidframework/core-interfaces";
|
|
7
|
+
import { ContainerErrorTypes } from "@fluidframework/container-definitions";
|
|
8
|
+
import {
|
|
9
|
+
IFluidErrorBase,
|
|
10
|
+
ITelemetryLoggerExt,
|
|
11
|
+
LoggingError,
|
|
12
|
+
wrapErrorAndLog,
|
|
13
|
+
} from "@fluidframework/telemetry-utils";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Warning emitted when requests to storage are being throttled.
|
|
17
|
+
*/
|
|
18
|
+
export class ThrottlingWarning extends LoggingError implements IThrottlingWarning, IFluidErrorBase {
|
|
19
|
+
/**
|
|
20
|
+
* {@inheritDoc @fluidframework/telemetry-utils#IFluidErrorBase.errorType}
|
|
21
|
+
*/
|
|
22
|
+
public readonly errorType = ContainerErrorTypes.throttlingError;
|
|
23
|
+
|
|
24
|
+
private constructor(
|
|
25
|
+
message: string,
|
|
26
|
+
readonly retryAfterSeconds: number,
|
|
27
|
+
props?: ITelemetryProperties,
|
|
28
|
+
) {
|
|
29
|
+
super(message, props);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Wrap the given error as a ThrottlingWarning
|
|
34
|
+
* Only preserves the error message, and applies the given retry after to the new warning object
|
|
35
|
+
*/
|
|
36
|
+
public static wrap(
|
|
37
|
+
error: unknown,
|
|
38
|
+
retryAfterSeconds: number,
|
|
39
|
+
logger: ITelemetryLoggerExt,
|
|
40
|
+
): IThrottlingWarning {
|
|
41
|
+
const newErrorFn = (errMsg: string) => new ThrottlingWarning(errMsg, retryAfterSeconds);
|
|
42
|
+
return wrapErrorAndLog(error, newErrorFn, logger);
|
|
43
|
+
}
|
|
44
|
+
}
|