@fluidframework/container-loader 1.1.0-75972 → 1.2.0-77818
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/dist/collabWindowTracker.js +1 -1
- package/dist/collabWindowTracker.js.map +1 -1
- package/dist/connectionManager.d.ts +10 -0
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +59 -21
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionState.d.ts +2 -2
- package/dist/connectionState.js +2 -2
- package/dist/connectionState.js.map +1 -1
- package/dist/container.d.ts +2 -1
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +15 -11
- package/dist/container.js.map +1 -1
- package/dist/deltaManager.d.ts +4 -0
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +8 -3
- package/dist/deltaManager.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/lib/collabWindowTracker.js +1 -1
- package/lib/collabWindowTracker.js.map +1 -1
- package/lib/connectionManager.d.ts +10 -0
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +59 -22
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionState.d.ts +2 -2
- package/lib/connectionState.js +2 -2
- package/lib/connectionState.js.map +1 -1
- package/lib/container.d.ts +2 -1
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +17 -13
- package/lib/container.js.map +1 -1
- package/lib/deltaManager.d.ts +4 -0
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +9 -4
- package/lib/deltaManager.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/package.json +14 -14
- package/src/collabWindowTracker.ts +1 -1
- package/src/connectionManager.ts +80 -20
- package/src/connectionState.ts +2 -2
- package/src/container.ts +33 -27
- package/src/deltaManager.ts +11 -2
- package/src/packageVersion.ts +1 -1
package/src/connectionManager.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { default as AbortController } from "abort-controller";
|
|
6
7
|
import {
|
|
7
8
|
IDisposable,
|
|
8
9
|
ITelemetryLogger,
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
waitForConnectedState,
|
|
31
32
|
DeltaStreamConnectionForbiddenError,
|
|
32
33
|
logNetworkFailure,
|
|
34
|
+
// isRuntimeMessage,
|
|
33
35
|
} from "@fluidframework/driver-utils";
|
|
34
36
|
import {
|
|
35
37
|
ConnectionMode,
|
|
@@ -118,6 +120,21 @@ class NoDeltaStream
|
|
|
118
120
|
public dispose() { this._disposed = true; }
|
|
119
121
|
}
|
|
120
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Interface to track the current in-progress connection attempt.
|
|
125
|
+
*/
|
|
126
|
+
interface IPendingConnection {
|
|
127
|
+
/**
|
|
128
|
+
* Used to cancel an in-progress connection attempt.
|
|
129
|
+
*/
|
|
130
|
+
abort(): void;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Desired ConnectionMode of this in-progress connection attempt.
|
|
134
|
+
*/
|
|
135
|
+
connectionMode: ConnectionMode;
|
|
136
|
+
}
|
|
137
|
+
|
|
121
138
|
/**
|
|
122
139
|
* Implementation of IConnectionManager, used by Container class
|
|
123
140
|
* Implements constant connectivity to relay service, by reconnecting in case of loast connection or error.
|
|
@@ -127,7 +144,12 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
127
144
|
/** Connection mode used when reconnecting on error or disconnect. */
|
|
128
145
|
private readonly defaultReconnectionMode: ConnectionMode;
|
|
129
146
|
|
|
130
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Tracks the current in-progress connection attempt. Undefined if there is none.
|
|
149
|
+
* Note: Once the connection attempt fires and the code becomes asynchronous, its possible that a new connection
|
|
150
|
+
* attempt was fired and this.pendingConnection was overwritten to reflect the new attempt.
|
|
151
|
+
*/
|
|
152
|
+
private pendingConnection: IPendingConnection | undefined;
|
|
131
153
|
private connection: IDocumentDeltaConnection | undefined;
|
|
132
154
|
|
|
133
155
|
/** file ACL - whether user has only read-only access to a file */
|
|
@@ -304,7 +326,7 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
304
326
|
}
|
|
305
327
|
this.closed = true;
|
|
306
328
|
|
|
307
|
-
this.pendingConnection =
|
|
329
|
+
this.pendingConnection = undefined;
|
|
308
330
|
|
|
309
331
|
// Ensure that things like triggerConnect() will short circuit
|
|
310
332
|
this._reconnectMode = ReconnectMode.Never;
|
|
@@ -411,11 +433,18 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
411
433
|
private async connectCore(connectionMode?: ConnectionMode): Promise<void> {
|
|
412
434
|
assert(!this.closed, 0x26a /* "not closed" */);
|
|
413
435
|
|
|
414
|
-
if (this.connection !== undefined
|
|
415
|
-
return;
|
|
436
|
+
if (this.connection !== undefined) {
|
|
437
|
+
return; // Connection attempt already completed successfully
|
|
416
438
|
}
|
|
417
439
|
|
|
418
|
-
let
|
|
440
|
+
let pendingConnectionMode;
|
|
441
|
+
if (this.pendingConnection !== undefined) {
|
|
442
|
+
pendingConnectionMode = this.pendingConnection.connectionMode;
|
|
443
|
+
this.cancelConnection(); // Throw out in-progress connection attempt in favor of new attempt
|
|
444
|
+
assert(this.pendingConnection === undefined, "this.pendingConnection should be undefined");
|
|
445
|
+
}
|
|
446
|
+
// If there is no specified ConnectionMode, try the previous mode, if there is no previous mode use default
|
|
447
|
+
let requestedMode = connectionMode ?? pendingConnectionMode ?? this.defaultReconnectionMode;
|
|
419
448
|
|
|
420
449
|
// if we have any non-acked ops from last connection, reconnect as "write".
|
|
421
450
|
// without that we would connect in view-only mode, which will result in immediate
|
|
@@ -433,31 +462,39 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
433
462
|
|
|
434
463
|
if (docService.policies?.storageOnly === true) {
|
|
435
464
|
connection = new NoDeltaStream();
|
|
436
|
-
// to keep setupNewSuccessfulConnection happy
|
|
437
|
-
this.pendingConnection = true;
|
|
438
465
|
this.setupNewSuccessfulConnection(connection, "read");
|
|
439
|
-
assert(
|
|
466
|
+
assert(this.pendingConnection === undefined, 0x2b3 /* "logic error" */);
|
|
440
467
|
return;
|
|
441
468
|
}
|
|
442
469
|
|
|
443
|
-
// this.pendingConnection resets to false as soon as we know the outcome of the connection attempt
|
|
444
|
-
this.pendingConnection = true;
|
|
445
|
-
|
|
446
470
|
let delayMs = InitialReconnectDelayInMs;
|
|
447
471
|
let connectRepeatCount = 0;
|
|
448
472
|
const connectStartTime = performance.now();
|
|
449
473
|
let lastError: any;
|
|
450
474
|
|
|
475
|
+
const abortController = new AbortController();
|
|
476
|
+
const abortSignal = abortController.signal;
|
|
477
|
+
this.pendingConnection = { abort: () => { abortController.abort(); }, connectionMode: requestedMode };
|
|
478
|
+
|
|
451
479
|
// This loop will keep trying to connect until successful, with a delay between each iteration.
|
|
452
480
|
while (connection === undefined) {
|
|
453
481
|
if (this.closed) {
|
|
454
482
|
throw new Error("Attempting to connect a closed DeltaManager");
|
|
455
483
|
}
|
|
484
|
+
if (abortSignal.aborted === true) {
|
|
485
|
+
this.logger.sendTelemetryEvent({
|
|
486
|
+
eventName: "ConnectionAttemptCancelled",
|
|
487
|
+
attempts: connectRepeatCount,
|
|
488
|
+
duration: TelemetryLogger.formatTick(performance.now() - connectStartTime),
|
|
489
|
+
connectionEstablished: false,
|
|
490
|
+
});
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
456
493
|
connectRepeatCount++;
|
|
457
494
|
|
|
458
495
|
try {
|
|
459
496
|
this.client.mode = requestedMode;
|
|
460
|
-
connection = await docService.connectToDeltaStream(this.client);
|
|
497
|
+
connection = await docService.connectToDeltaStream({ ...this.client, mode: requestedMode });
|
|
461
498
|
|
|
462
499
|
if (connection.disposed) {
|
|
463
500
|
// Nobody observed this connection, so drop it on the floor and retry.
|
|
@@ -515,6 +552,18 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
515
552
|
);
|
|
516
553
|
}
|
|
517
554
|
|
|
555
|
+
// Check for abort signal after while loop as well
|
|
556
|
+
if (abortSignal.aborted === true) {
|
|
557
|
+
connection.dispose();
|
|
558
|
+
this.logger.sendTelemetryEvent({
|
|
559
|
+
eventName: "ConnectionAttemptCancelled",
|
|
560
|
+
attempts: connectRepeatCount,
|
|
561
|
+
duration: TelemetryLogger.formatTick(performance.now() - connectStartTime),
|
|
562
|
+
connectionEstablished: true,
|
|
563
|
+
});
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
|
|
518
567
|
this.setupNewSuccessfulConnection(connection, requestedMode);
|
|
519
568
|
}
|
|
520
569
|
|
|
@@ -534,15 +583,20 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
534
583
|
/**
|
|
535
584
|
* Disconnect the current connection.
|
|
536
585
|
* @param reason - Text description of disconnect reason to emit with disconnect event
|
|
586
|
+
* @returns A boolean that indicates if there was an existing connection (or pending connection) to disconnect
|
|
537
587
|
*/
|
|
538
588
|
private disconnectFromDeltaStream(reason: string): boolean {
|
|
539
589
|
this.pendingReconnect = false;
|
|
540
590
|
|
|
541
591
|
if (this.connection === undefined) {
|
|
592
|
+
if (this.pendingConnection !== undefined) {
|
|
593
|
+
this.cancelConnection();
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
542
596
|
return false;
|
|
543
597
|
}
|
|
544
598
|
|
|
545
|
-
assert(
|
|
599
|
+
assert(this.pendingConnection === undefined, 0x27b /* "reentrancy may result in incorrect behavior" */);
|
|
546
600
|
|
|
547
601
|
const connection = this.connection;
|
|
548
602
|
// Avoid any re-entrancy - clear object reference
|
|
@@ -568,6 +622,16 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
568
622
|
return true;
|
|
569
623
|
}
|
|
570
624
|
|
|
625
|
+
/**
|
|
626
|
+
* Cancel in-progress connection attempt.
|
|
627
|
+
*/
|
|
628
|
+
private cancelConnection() {
|
|
629
|
+
assert(this.pendingConnection !== undefined, "this.pendingConnection is undefined when trying to cancel");
|
|
630
|
+
this.pendingConnection.abort();
|
|
631
|
+
this.pendingConnection = undefined;
|
|
632
|
+
this.logger.sendTelemetryEvent({ eventName: "ConnectionCancelReceived" });
|
|
633
|
+
}
|
|
634
|
+
|
|
571
635
|
/**
|
|
572
636
|
* Once we've successfully gotten a connection, we need to set up state, attach event listeners, and process
|
|
573
637
|
* initial messages.
|
|
@@ -578,11 +642,8 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
578
642
|
assert(this.connection === undefined, 0x0e6 /* "old connection exists on new connection setup" */);
|
|
579
643
|
assert(!connection.disposed, 0x28a /* "can't be disposed - Callers need to ensure that!" */);
|
|
580
644
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
} else {
|
|
584
|
-
assert(this.closed, 0x27f /* "reentrancy may result in incorrect behavior" */);
|
|
585
|
-
}
|
|
645
|
+
this.pendingConnection = undefined;
|
|
646
|
+
|
|
586
647
|
this.connection = connection;
|
|
587
648
|
|
|
588
649
|
// Does information in scopes & mode matches?
|
|
@@ -780,7 +841,6 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
780
841
|
|
|
781
842
|
public sendMessages(messages: IDocumentMessage[]) {
|
|
782
843
|
assert(this.connected, 0x2b4 /* "not connected on sending ops!" */);
|
|
783
|
-
|
|
784
844
|
// If connection is "read" or implicit "read" (got leave op for "write" connection),
|
|
785
845
|
// then op can't make it through - we will get a nack if op is sent.
|
|
786
846
|
// We can short-circuit this process.
|
|
@@ -832,7 +892,7 @@ export class ConnectionManager implements IConnectionManager {
|
|
|
832
892
|
this.logger.sendPerformanceEvent({ eventName: "ReadConnectionTransition" });
|
|
833
893
|
|
|
834
894
|
// Please see #8483 for more details on why maintaining connection further as is would not work.
|
|
835
|
-
// Short story - connection properties are immutable, and many processes (consensus
|
|
895
|
+
// Short story - connection properties are immutable, and many processes (consensus DDSes, summarizer)
|
|
836
896
|
// assume that connection stays "write" connection until disconnect, and act accordingly, which may
|
|
837
897
|
// not work well with de-facto "read" connection we are in after receiving own leave op on timeout.
|
|
838
898
|
// Clients need to be able to transition to "read" state after some time of inactivity!
|
package/src/connectionState.ts
CHANGED
|
@@ -18,8 +18,8 @@ export enum ConnectionState {
|
|
|
18
18
|
EstablishingConnection = 3,
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* @
|
|
22
|
-
* @deprecated - This state itself is not gone, just being renamed. Please use ConnectionState.CatchingUp.
|
|
21
|
+
* See {@link ConnectionState.CatchingUp}, which is the new name for this state.
|
|
22
|
+
* @deprecated - This state itself is not gone, just being renamed. Please use {@link ConnectionState.CatchingUp}.
|
|
23
23
|
*/
|
|
24
24
|
Connecting = 1,
|
|
25
25
|
|
package/src/container.ts
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
extractSafePropertiesFromMessage,
|
|
36
36
|
GenericError,
|
|
37
37
|
UsageError,
|
|
38
|
-
|
|
38
|
+
} from "@fluidframework/container-utils";
|
|
39
39
|
import {
|
|
40
40
|
IDocumentService,
|
|
41
41
|
IDocumentStorageService,
|
|
@@ -50,9 +50,10 @@ import {
|
|
|
50
50
|
combineAppAndProtocolSummary,
|
|
51
51
|
runWithRetry,
|
|
52
52
|
isFluidResolvedUrl,
|
|
53
|
+
isRuntimeMessage,
|
|
54
|
+
isUnpackedRuntimeMessage,
|
|
53
55
|
} from "@fluidframework/driver-utils";
|
|
54
56
|
import {
|
|
55
|
-
isSystemMessage,
|
|
56
57
|
IProtocolHandler,
|
|
57
58
|
ProtocolOpHandlerWithClientValidation,
|
|
58
59
|
} from "@fluidframework/protocol-base";
|
|
@@ -217,7 +218,9 @@ export async function waitContainerToCatchUp(container: IContainer) {
|
|
|
217
218
|
};
|
|
218
219
|
container.on(connectedEventName, callback);
|
|
219
220
|
|
|
220
|
-
container.
|
|
221
|
+
if (container.connectionState === ConnectionState.Disconnected) {
|
|
222
|
+
container.connect();
|
|
223
|
+
}
|
|
221
224
|
});
|
|
222
225
|
}
|
|
223
226
|
|
|
@@ -286,14 +289,14 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
286
289
|
event.end({ ...props, ...loadOptions.loadMode });
|
|
287
290
|
resolve(container);
|
|
288
291
|
},
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
292
|
+
(error) => {
|
|
293
|
+
const err = normalizeError(error);
|
|
294
|
+
// Depending where error happens, we can be attempting to connect to web socket
|
|
295
|
+
// and continuously retrying (consider offline mode)
|
|
296
|
+
// Host has no container to close, so it's prudent to do it here
|
|
297
|
+
container.close(err);
|
|
298
|
+
onClosed(err);
|
|
299
|
+
});
|
|
297
300
|
}),
|
|
298
301
|
{ start: true, end: true, cancel: "generic" },
|
|
299
302
|
);
|
|
@@ -401,7 +404,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
401
404
|
return this._protocolHandler;
|
|
402
405
|
}
|
|
403
406
|
|
|
404
|
-
|
|
407
|
+
/** During initialization we pause the inbound queues. We track this state to ensure we only call resume once */
|
|
408
|
+
private inboundQueuePausedFromInit = true;
|
|
405
409
|
private firstConnection = true;
|
|
406
410
|
private readonly connectionTransitionTimes: number[] = [];
|
|
407
411
|
private messageCountAfterDisconnection: number = 0;
|
|
@@ -535,7 +539,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
535
539
|
name: typeof name === "string" ? name : undefined,
|
|
536
540
|
},
|
|
537
541
|
error);
|
|
538
|
-
|
|
542
|
+
});
|
|
539
543
|
this._audience = new Audience();
|
|
540
544
|
|
|
541
545
|
this.clientDetailsOverride = config.clientDetailsOverride;
|
|
@@ -678,10 +682,10 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
678
682
|
}
|
|
679
683
|
break;
|
|
680
684
|
case connectedEventName:
|
|
681
|
-
|
|
685
|
+
if (this.connected) {
|
|
682
686
|
listener(this.clientId);
|
|
683
|
-
|
|
684
|
-
|
|
687
|
+
}
|
|
688
|
+
break;
|
|
685
689
|
case disconnectedEventName:
|
|
686
690
|
if (!this.connected) {
|
|
687
691
|
listener();
|
|
@@ -913,7 +917,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
913
917
|
throw newError;
|
|
914
918
|
}
|
|
915
919
|
},
|
|
916
|
-
|
|
920
|
+
{ start: true, end: true, cancel: "generic" });
|
|
917
921
|
}
|
|
918
922
|
|
|
919
923
|
public async request(path: IRequest): Promise<IResponse> {
|
|
@@ -992,8 +996,8 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
992
996
|
assert(!this.closed, 0x0d9 /* "Attempting to connect() a closed DeltaManager" */);
|
|
993
997
|
|
|
994
998
|
// Resume processing ops
|
|
995
|
-
if (
|
|
996
|
-
this.
|
|
999
|
+
if (this.inboundQueuePausedFromInit) {
|
|
1000
|
+
this.inboundQueuePausedFromInit = false;
|
|
997
1001
|
this._deltaManager.inbound.resume();
|
|
998
1002
|
this._deltaManager.inboundSignal.resume();
|
|
999
1003
|
}
|
|
@@ -1189,13 +1193,9 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1189
1193
|
|
|
1190
1194
|
switch (loadMode.deltaConnection) {
|
|
1191
1195
|
case undefined:
|
|
1192
|
-
// Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler().
|
|
1193
|
-
// If there is gap, we will learn about it once connected, but the gap should be small (if any),
|
|
1194
|
-
// assuming that resumeInternal() is called quickly after initial container boot.
|
|
1195
|
-
this.resumeInternal({ reason: "DocumentLoad", fetchOpsFromStorage: false });
|
|
1196
|
-
break;
|
|
1197
1196
|
case "delayed":
|
|
1198
|
-
this.
|
|
1197
|
+
assert(this.inboundQueuePausedFromInit, "inboundQueuePausedFromInit should be true");
|
|
1198
|
+
this.inboundQueuePausedFromInit = false;
|
|
1199
1199
|
this._deltaManager.inbound.resume();
|
|
1200
1200
|
this._deltaManager.inboundSignal.resume();
|
|
1201
1201
|
break;
|
|
@@ -1395,7 +1395,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1395
1395
|
if (key === "code" || key === "code2") {
|
|
1396
1396
|
if (!isFluidCodeDetails(value)) {
|
|
1397
1397
|
this.mc.logger.sendErrorEvent({
|
|
1398
|
-
|
|
1398
|
+
eventName: "CodeProposalNotIFluidCodeDetails",
|
|
1399
1399
|
});
|
|
1400
1400
|
}
|
|
1401
1401
|
this.processCodeProposal().catch((error) => {
|
|
@@ -1684,8 +1684,14 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
|
|
|
1684
1684
|
new DataCorruptionError(errorMessage, extractSafePropertiesFromMessage(message))));
|
|
1685
1685
|
}
|
|
1686
1686
|
|
|
1687
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
1688
|
+
if (isUnpackedRuntimeMessage(message) && !isRuntimeMessage(message)) {
|
|
1689
|
+
this.mc.logger.sendTelemetryEvent(
|
|
1690
|
+
{ eventName: "UnpackedRuntimeMessage", type: message.type });
|
|
1691
|
+
}
|
|
1687
1692
|
// Forward non system messages to the loaded runtime for processing
|
|
1688
|
-
|
|
1693
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
1694
|
+
if (isRuntimeMessage(message) || isUnpackedRuntimeMessage(message)) {
|
|
1689
1695
|
this.context.process(message, local, undefined);
|
|
1690
1696
|
}
|
|
1691
1697
|
|
package/src/deltaManager.ts
CHANGED
|
@@ -31,7 +31,6 @@ import {
|
|
|
31
31
|
IDocumentService,
|
|
32
32
|
DriverErrorType,
|
|
33
33
|
} from "@fluidframework/driver-definitions";
|
|
34
|
-
import { isSystemMessage } from "@fluidframework/protocol-base";
|
|
35
34
|
import {
|
|
36
35
|
IDocumentMessage,
|
|
37
36
|
ISequencedDocumentMessage,
|
|
@@ -41,6 +40,7 @@ import {
|
|
|
41
40
|
} from "@fluidframework/protocol-definitions";
|
|
42
41
|
import {
|
|
43
42
|
NonRetryableError,
|
|
43
|
+
isClientMessage,
|
|
44
44
|
} from "@fluidframework/driver-utils";
|
|
45
45
|
import {
|
|
46
46
|
ThrottlingWarning,
|
|
@@ -105,6 +105,10 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
105
105
|
private lastProcessedMessage: ISequencedDocumentMessage | undefined;
|
|
106
106
|
private baseTerm: number = 0;
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Track down the ops size.
|
|
110
|
+
*/
|
|
111
|
+
private opsSize: number = 0;
|
|
108
112
|
private prevEnqueueMessagesReason: string | undefined;
|
|
109
113
|
private previouslyProcessedMessage: ISequencedDocumentMessage | undefined;
|
|
110
114
|
|
|
@@ -198,6 +202,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
198
202
|
return -1;
|
|
199
203
|
}
|
|
200
204
|
|
|
205
|
+
this.opsSize += message.contents.length;
|
|
206
|
+
|
|
201
207
|
this.messageBuffer.push(message);
|
|
202
208
|
|
|
203
209
|
this.emit("submitOp", message);
|
|
@@ -226,6 +232,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
226
232
|
public get connectionProps(): ITelemetryProperties {
|
|
227
233
|
return {
|
|
228
234
|
sequenceNumber: this.lastSequenceNumber,
|
|
235
|
+
opsSize: this.opsSize > 0 ? this.opsSize : undefined,
|
|
229
236
|
...this.connectionManager.connectionProps,
|
|
230
237
|
};
|
|
231
238
|
}
|
|
@@ -337,6 +344,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
337
344
|
// state. As requirements change, so should these checks.
|
|
338
345
|
assert(this.messageBuffer.length === 0, 0x0e9 /* "messageBuffer is not empty on new connection" */);
|
|
339
346
|
|
|
347
|
+
this.opsSize = 0;
|
|
348
|
+
|
|
340
349
|
this.emit(
|
|
341
350
|
"connect",
|
|
342
351
|
connection,
|
|
@@ -753,7 +762,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
753
762
|
// System messages may have no clientId (but some do, like propose, noop, summarize)
|
|
754
763
|
assert(
|
|
755
764
|
message.clientId !== undefined
|
|
756
|
-
||
|
|
765
|
+
|| !(isClientMessage(message)),
|
|
757
766
|
0x0ed /* "non-system message have to have clientId" */,
|
|
758
767
|
);
|
|
759
768
|
|
package/src/packageVersion.ts
CHANGED