@fluidframework/container-loader 1.2.6 → 1.3.0-97515
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/.eslintrc.js +21 -8
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +21 -4
- package/dist/container.js.map +1 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +6 -6
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaManagerProxy.d.ts +4 -1
- package/dist/deltaManagerProxy.d.ts.map +1 -1
- package/dist/deltaQueue.d.ts +9 -2
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +31 -26
- package/dist/deltaQueue.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +21 -4
- package/lib/container.js.map +1 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +6 -6
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaManagerProxy.d.ts +4 -1
- package/lib/deltaManagerProxy.d.ts.map +1 -1
- package/lib/deltaQueue.d.ts +9 -2
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +32 -27
- package/lib/deltaQueue.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +13 -11
- package/src/container.ts +34 -6
- package/src/deltaManager.ts +6 -4
- package/src/deltaQueue.ts +34 -28
- package/src/packageVersion.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,qCAAqC,CAAC;AAC1D,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,qCAAqC,CAAC;AAC1D,eAAO,MAAM,UAAU,gBAAgB,CAAC"}
|
package/lib/packageVersion.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,kCAAkC,CAAC;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-loader\";\nexport const pkgVersion = \"1.3.0-97515\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/container-loader",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0-97515",
|
|
4
4
|
"description": "Fluid container loader",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -63,26 +63,28 @@
|
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@fluidframework/common-definitions": "^0.20.1",
|
|
65
65
|
"@fluidframework/common-utils": "^0.32.1",
|
|
66
|
-
"@fluidframework/container-definitions": "
|
|
67
|
-
"@fluidframework/container-utils": "
|
|
68
|
-
"@fluidframework/core-interfaces": "
|
|
69
|
-
"@fluidframework/driver-definitions": "
|
|
70
|
-
"@fluidframework/driver-utils": "
|
|
66
|
+
"@fluidframework/container-definitions": "1.3.0-97515",
|
|
67
|
+
"@fluidframework/container-utils": "1.3.0-97515",
|
|
68
|
+
"@fluidframework/core-interfaces": "1.3.0-97515",
|
|
69
|
+
"@fluidframework/driver-definitions": "1.3.0-97515",
|
|
70
|
+
"@fluidframework/driver-utils": "1.3.0-97515",
|
|
71
71
|
"@fluidframework/protocol-base": "^0.1036.5000",
|
|
72
72
|
"@fluidframework/protocol-definitions": "^0.1028.2000",
|
|
73
|
-
"@fluidframework/telemetry-utils": "
|
|
73
|
+
"@fluidframework/telemetry-utils": "1.3.0-97515",
|
|
74
74
|
"abort-controller": "^3.0.0",
|
|
75
75
|
"double-ended-queue": "^2.1.0-0",
|
|
76
|
+
"events": "^3.1.0",
|
|
76
77
|
"lodash": "^4.17.21",
|
|
78
|
+
"url": "^0.11.0",
|
|
77
79
|
"uuid": "^8.3.1"
|
|
78
80
|
},
|
|
79
81
|
"devDependencies": {
|
|
80
82
|
"@fluidframework/build-common": "^0.24.0",
|
|
81
83
|
"@fluidframework/build-tools": "^0.2.74327",
|
|
82
|
-
"@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader
|
|
84
|
+
"@fluidframework/container-loader-previous": "npm:@fluidframework/container-loader@^1.2.0",
|
|
83
85
|
"@fluidframework/eslint-config-fluid": "^0.28.2000",
|
|
84
|
-
"@fluidframework/mocha-test-setup": "
|
|
85
|
-
"@fluidframework/test-loader-utils": "
|
|
86
|
+
"@fluidframework/mocha-test-setup": "1.3.0-97515",
|
|
87
|
+
"@fluidframework/test-loader-utils": "1.3.0-97515",
|
|
86
88
|
"@microsoft/api-extractor": "^7.22.2",
|
|
87
89
|
"@rushstack/eslint-config": "^2.5.1",
|
|
88
90
|
"@types/double-ended-queue": "^2.1.0",
|
|
@@ -102,7 +104,7 @@
|
|
|
102
104
|
"typescript-formatter": "7.1.0"
|
|
103
105
|
},
|
|
104
106
|
"typeValidation": {
|
|
105
|
-
"version": "1.
|
|
107
|
+
"version": "1.3.0",
|
|
106
108
|
"broken": {}
|
|
107
109
|
}
|
|
108
110
|
}
|
package/src/container.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import merge from "lodash/merge";
|
|
8
8
|
import { v4 as uuid } from "uuid";
|
|
9
9
|
import {
|
|
10
|
-
IDisposable, ITelemetryProperties,
|
|
10
|
+
IDisposable, ITelemetryLogger, ITelemetryProperties,
|
|
11
11
|
} from "@fluidframework/common-definitions";
|
|
12
12
|
import { assert, performance, unreachableCase } from "@fluidframework/common-utils";
|
|
13
13
|
import {
|
|
@@ -228,6 +228,24 @@ const getCodeProposal =
|
|
|
228
228
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
229
229
|
(quorum: IQuorumProposals) => quorum.get("code") ?? quorum.get("code2");
|
|
230
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Helper function to report to telemetry cases where operation takes longer than expected (1s)
|
|
233
|
+
* @param logger - logger to use
|
|
234
|
+
* @param eventName - event name
|
|
235
|
+
* @param action - functor to call and measure
|
|
236
|
+
*/
|
|
237
|
+
async function ReportIfTooLong(
|
|
238
|
+
logger: ITelemetryLogger,
|
|
239
|
+
eventName: string,
|
|
240
|
+
action: () => Promise<ITelemetryProperties>,
|
|
241
|
+
) {
|
|
242
|
+
const event = PerformanceEvent.start(logger, { eventName });
|
|
243
|
+
const props = await action();
|
|
244
|
+
if (event.duration > 1000) {
|
|
245
|
+
event.end(props);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
231
249
|
/**
|
|
232
250
|
* State saved by a container at close time, to be used to load a new instance
|
|
233
251
|
* of the container to the same state
|
|
@@ -566,6 +584,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
566
584
|
containerAttachState: () => this._attachState,
|
|
567
585
|
containerLifecycleState: () => this._lifecycleState,
|
|
568
586
|
containerConnectionState: () => ConnectionState[this.connectionState],
|
|
587
|
+
serializedContainer: config.serializedContainerState !== undefined,
|
|
569
588
|
},
|
|
570
589
|
// we need to be judicious with our logging here to avoid generating too much data
|
|
571
590
|
// all data logged here should be broadly applicable, and not specific to a
|
|
@@ -578,6 +597,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
578
597
|
containerLoadedFromVersionId: () => this.loadedFromVersion?.id,
|
|
579
598
|
containerLoadedFromVersionDate: () => this.loadedFromVersion?.date,
|
|
580
599
|
// message information to associate errors with the specific execution state
|
|
600
|
+
// dmLastMsqSeqNumber: if present, same as dmLastProcessedSeqNumber
|
|
581
601
|
dmLastMsqSeqNumber: () => this.deltaManager?.lastMessage?.sequenceNumber,
|
|
582
602
|
dmLastMsqSeqTimestamp: () => this.deltaManager?.lastMessage?.timestamp,
|
|
583
603
|
dmLastMsqSeqClientId: () => this.deltaManager?.lastMessage?.clientId,
|
|
@@ -1175,17 +1195,20 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1175
1195
|
pendingLocalState?.pendingRuntimeState,
|
|
1176
1196
|
);
|
|
1177
1197
|
|
|
1178
|
-
// Internal context is fully loaded at this point
|
|
1179
|
-
this.setLoaded();
|
|
1180
|
-
|
|
1181
1198
|
// We might have hit some failure that did not manifest itself in exception in this flow,
|
|
1182
1199
|
// do not start op processing in such case - static version of Container.load() will handle it correctly.
|
|
1183
1200
|
if (!this.closed) {
|
|
1184
1201
|
if (opsBeforeReturnP !== undefined) {
|
|
1185
1202
|
this._deltaManager.inbound.resume();
|
|
1186
1203
|
|
|
1187
|
-
await
|
|
1188
|
-
|
|
1204
|
+
await ReportIfTooLong(
|
|
1205
|
+
this.mc.logger,
|
|
1206
|
+
"WaitOps",
|
|
1207
|
+
async () => { await opsBeforeReturnP; return {}; });
|
|
1208
|
+
await ReportIfTooLong(
|
|
1209
|
+
this.mc.logger,
|
|
1210
|
+
"WaitOpProcessing",
|
|
1211
|
+
async () => this._deltaManager.inbound.waitTillProcessingDone());
|
|
1189
1212
|
|
|
1190
1213
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1191
1214
|
this._deltaManager.inbound.pause();
|
|
@@ -1215,9 +1238,14 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1215
1238
|
throw new Error("Container was closed while load()");
|
|
1216
1239
|
}
|
|
1217
1240
|
|
|
1241
|
+
// Internal context is fully loaded at this point
|
|
1242
|
+
this.setLoaded();
|
|
1243
|
+
|
|
1218
1244
|
return {
|
|
1219
1245
|
sequenceNumber: attributes.sequenceNumber,
|
|
1220
1246
|
version: versionId,
|
|
1247
|
+
dmLastProcessedSeqNumber: this._deltaManager.lastSequenceNumber,
|
|
1248
|
+
dmLastKnownSeqNumber: this._deltaManager.lastKnownSeqNumber,
|
|
1221
1249
|
};
|
|
1222
1250
|
}
|
|
1223
1251
|
|
package/src/deltaManager.ts
CHANGED
|
@@ -410,7 +410,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
410
410
|
|
|
411
411
|
if (prefetchType !== "none") {
|
|
412
412
|
const cacheOnly = prefetchType === "cached";
|
|
413
|
-
await this.fetchMissingDeltasCore(
|
|
413
|
+
await this.fetchMissingDeltasCore(`DocumentOpen_${prefetchType}`, cacheOnly);
|
|
414
414
|
|
|
415
415
|
// Keep going with fetching ops from storage once we have all cached ops in.
|
|
416
416
|
// But do not block load and make this request async / not blocking this api.
|
|
@@ -418,7 +418,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
418
418
|
// (which in most cases will happen when we are done processing cached ops)
|
|
419
419
|
if (cacheOnly) {
|
|
420
420
|
// fire and forget
|
|
421
|
-
this.fetchMissingDeltas("
|
|
421
|
+
this.fetchMissingDeltas("PostDocumentOpen");
|
|
422
422
|
}
|
|
423
423
|
}
|
|
424
424
|
|
|
@@ -453,6 +453,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
453
453
|
private async getDeltas(
|
|
454
454
|
from: number, // inclusive
|
|
455
455
|
to: number | undefined, // exclusive
|
|
456
|
+
fetchReason: string,
|
|
456
457
|
callback: (messages: ISequencedDocumentMessage[]) => void,
|
|
457
458
|
cacheOnly: boolean) {
|
|
458
459
|
const docService = this.serviceProvider();
|
|
@@ -473,7 +474,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
473
474
|
// received through delta stream. Validate that before moving forward.
|
|
474
475
|
if (this.lastQueuedSequenceNumber >= lastExpectedOp) {
|
|
475
476
|
this.logger.sendPerformanceEvent({
|
|
476
|
-
reason:
|
|
477
|
+
reason: fetchReason,
|
|
477
478
|
eventName: "ExtraStorageCall",
|
|
478
479
|
early: true,
|
|
479
480
|
from,
|
|
@@ -521,7 +522,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
521
522
|
to, // exclusive
|
|
522
523
|
controller.signal,
|
|
523
524
|
cacheOnly,
|
|
524
|
-
|
|
525
|
+
fetchReason);
|
|
525
526
|
|
|
526
527
|
// eslint-disable-next-line no-constant-condition
|
|
527
528
|
while (true) {
|
|
@@ -876,6 +877,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
876
877
|
await this.getDeltas(
|
|
877
878
|
from,
|
|
878
879
|
to,
|
|
880
|
+
fetchReason,
|
|
879
881
|
(messages) => {
|
|
880
882
|
this.refreshDelayInfo(this.deltaStorageDelayId);
|
|
881
883
|
this.enqueueMessages(messages, fetchReason);
|
package/src/deltaQueue.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IDeltaQueue, IDeltaQueueEvents } from "@fluidframework/container-definitions";
|
|
7
|
-
import { assert, performance,
|
|
7
|
+
import { assert, performance, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
8
8
|
import Deque from "double-ended-queue";
|
|
9
9
|
|
|
10
10
|
export interface IDeltaQueueWriter<T> {
|
|
@@ -30,7 +30,7 @@ export class DeltaQueue<T>
|
|
|
30
30
|
* When processing is ongoing, holds a deferred that will resolve once processing stops.
|
|
31
31
|
* Undefined when not processing.
|
|
32
32
|
*/
|
|
33
|
-
private
|
|
33
|
+
private processingPromise: Promise<{ count: number; duration: number; }> | undefined;
|
|
34
34
|
|
|
35
35
|
public get disposed(): boolean {
|
|
36
36
|
return this.isDisposed;
|
|
@@ -48,13 +48,11 @@ export class DeltaQueue<T>
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
public get idle(): boolean {
|
|
51
|
-
return this.
|
|
51
|
+
return this.processingPromise === undefined && this.q.length === 0;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
public async waitTillProcessingDone()
|
|
55
|
-
|
|
56
|
-
return this.processingDeferred.promise;
|
|
57
|
-
}
|
|
54
|
+
public async waitTillProcessingDone() {
|
|
55
|
+
return this.processingPromise ?? { count: 0, duration: 0 };
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
/**
|
|
@@ -98,7 +96,7 @@ export class DeltaQueue<T>
|
|
|
98
96
|
this.pauseCount++;
|
|
99
97
|
// If called from within the processing loop, we are in the middle of processing an op. Return a promise
|
|
100
98
|
// that will resolve when processing has actually stopped.
|
|
101
|
-
|
|
99
|
+
await this.waitTillProcessingDone();
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
public resume(): void {
|
|
@@ -113,20 +111,31 @@ export class DeltaQueue<T>
|
|
|
113
111
|
* not already started.
|
|
114
112
|
*/
|
|
115
113
|
private ensureProcessing() {
|
|
116
|
-
if (
|
|
117
|
-
this.processingDeferred = new Deferred<void>();
|
|
114
|
+
if (this.anythingToProcess() && this.processingPromise === undefined) {
|
|
118
115
|
// Use a resolved promise to start the processing on a separate stack.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
this.processDeltas();
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
this.processingPromise = Promise.resolve().then(() => {
|
|
117
|
+
assert(this.processingPromise !== undefined, "reentrancy?");
|
|
118
|
+
const result = this.processDeltas();
|
|
119
|
+
assert(this.processingPromise !== undefined, "reentrancy?");
|
|
120
|
+
// WARNING: Do not move next line to .finally() clause!
|
|
121
|
+
// It runs async and creates a race condition where incoming ensureProcessing() call observes
|
|
122
|
+
// from previous run while previous run is over (but finally clause was not scheduled yet)
|
|
123
|
+
this.processingPromise = undefined;
|
|
124
|
+
return result;
|
|
125
|
+
}).catch((error) => {
|
|
126
|
+
this.error = error;
|
|
127
|
+
this.processingPromise = undefined;
|
|
128
|
+
this.emit("error", error);
|
|
129
|
+
return { count: 0, duration: 0 };
|
|
126
130
|
});
|
|
131
|
+
assert(this.processingPromise !== undefined, "processDeltas() should run async");
|
|
127
132
|
}
|
|
128
133
|
}
|
|
129
134
|
|
|
135
|
+
private anythingToProcess() {
|
|
136
|
+
return this.q.length !== 0 && !this.paused && this.error === undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
130
139
|
/**
|
|
131
140
|
* Executes the delta processing loop until a stop condition is reached.
|
|
132
141
|
*/
|
|
@@ -136,24 +145,21 @@ export class DeltaQueue<T>
|
|
|
136
145
|
|
|
137
146
|
// For grouping to work we must process all local messages immediately and in the single turn.
|
|
138
147
|
// So loop over them until no messages to process, we have become paused, or hit an error.
|
|
139
|
-
while (
|
|
148
|
+
while (this.anythingToProcess()) {
|
|
140
149
|
// Get the next message in the queue
|
|
141
150
|
const next = this.q.shift();
|
|
142
151
|
count++;
|
|
143
152
|
// Process the message.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.emit("op", next);
|
|
149
|
-
} catch (error) {
|
|
150
|
-
this.error = error;
|
|
151
|
-
this.emit("error", error);
|
|
152
|
-
}
|
|
153
|
+
// We know next is defined since we did a length check just prior to shifting.
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
155
|
+
this.worker(next!);
|
|
156
|
+
this.emit("op", next);
|
|
153
157
|
}
|
|
154
158
|
|
|
159
|
+
const duration = performance.now() - start;
|
|
155
160
|
if (this.q.length === 0) {
|
|
156
|
-
this.emit("idle", count,
|
|
161
|
+
this.emit("idle", count, duration);
|
|
157
162
|
}
|
|
163
|
+
return { count, duration };
|
|
158
164
|
}
|
|
159
165
|
}
|
package/src/packageVersion.ts
CHANGED