@fluidframework/container-loader 2.0.0-internal.5.3.2 → 2.0.0-internal.5.4.0
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 +4 -0
- package/README.md +6 -3
- package/dist/audience.d.ts +1 -0
- package/dist/audience.d.ts.map +1 -1
- package/dist/audience.js +3 -1
- package/dist/audience.js.map +1 -1
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +6 -11
- package/dist/connectionManager.js.map +1 -1
- package/dist/container.d.ts +2 -3
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +57 -75
- package/dist/container.js.map +1 -1
- package/dist/debugLogger.d.ts +30 -0
- package/dist/debugLogger.d.ts.map +1 -0
- package/dist/debugLogger.js +96 -0
- package/dist/debugLogger.js.map +1 -0
- package/dist/deltaManager.d.ts +0 -1
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +17 -9
- package/dist/deltaManager.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +16 -5
- package/dist/loader.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/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/lib/audience.d.ts +1 -0
- package/lib/audience.d.ts.map +1 -1
- package/lib/audience.js +3 -1
- package/lib/audience.js.map +1 -1
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +7 -9
- package/lib/connectionManager.js.map +1 -1
- package/lib/container.d.ts +2 -3
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +59 -77
- package/lib/container.js.map +1 -1
- package/lib/debugLogger.d.ts +30 -0
- package/lib/debugLogger.d.ts.map +1 -0
- package/lib/debugLogger.js +92 -0
- package/lib/debugLogger.js.map +1 -0
- package/lib/deltaManager.d.ts +0 -1
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +15 -4
- package/lib/deltaManager.js.map +1 -1
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +16 -5
- package/lib/loader.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/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/package.json +12 -12
- package/src/audience.ts +6 -0
- package/src/connectionManager.ts +7 -12
- package/src/container.ts +65 -92
- package/src/debugLogger.ts +113 -0
- package/src/deltaManager.ts +28 -4
- package/src/loader.ts +16 -7
- package/src/packageVersion.ts +1 -1
- package/src/quorum.ts +0 -10
package/src/container.ts
CHANGED
|
@@ -85,17 +85,17 @@ import {
|
|
|
85
85
|
SummaryType,
|
|
86
86
|
} from "@fluidframework/protocol-definitions";
|
|
87
87
|
import {
|
|
88
|
-
|
|
88
|
+
createChildLogger,
|
|
89
89
|
EventEmitterWithErrorHandling,
|
|
90
90
|
PerformanceEvent,
|
|
91
91
|
raiseConnectedEvent,
|
|
92
|
-
TelemetryLogger,
|
|
93
92
|
connectedEventName,
|
|
94
93
|
normalizeError,
|
|
95
94
|
MonitoringContext,
|
|
96
|
-
|
|
95
|
+
createChildMonitoringContext,
|
|
97
96
|
wrapError,
|
|
98
97
|
ITelemetryLoggerExt,
|
|
98
|
+
formatTick,
|
|
99
99
|
} from "@fluidframework/telemetry-utils";
|
|
100
100
|
import { Audience } from "./audience";
|
|
101
101
|
import { ContainerContext } from "./containerContext";
|
|
@@ -111,7 +111,7 @@ import {
|
|
|
111
111
|
} from "./containerStorageAdapter";
|
|
112
112
|
import { IConnectionStateHandler, createConnectionStateHandler } from "./connectionStateHandler";
|
|
113
113
|
import { getProtocolSnapshotTree, getSnapshotTreeFromSerializedContainer } from "./utils";
|
|
114
|
-
import { initQuorumValuesFromCodeDetails
|
|
114
|
+
import { initQuorumValuesFromCodeDetails } from "./quorum";
|
|
115
115
|
import { NoopHeuristic } from "./noopHeuristic";
|
|
116
116
|
import { ConnectionManager } from "./connectionManager";
|
|
117
117
|
import { ConnectionState } from "./connectionState";
|
|
@@ -473,7 +473,7 @@ export class Container
|
|
|
473
473
|
private readonly codeLoader: ICodeDetailsLoader;
|
|
474
474
|
private readonly options: ILoaderOptions;
|
|
475
475
|
private readonly scope: FluidObject;
|
|
476
|
-
private readonly subLogger:
|
|
476
|
+
private readonly subLogger: ITelemetryLoggerExt;
|
|
477
477
|
private readonly detachedBlobStorage: IDetachedBlobStorage | undefined;
|
|
478
478
|
private readonly protocolHandlerBuilder: ProtocolHandlerBuilder;
|
|
479
479
|
|
|
@@ -523,13 +523,14 @@ export class Container
|
|
|
523
523
|
|
|
524
524
|
public get closed(): boolean {
|
|
525
525
|
return (
|
|
526
|
-
this._lifecycleState === "closing" ||
|
|
527
|
-
this._lifecycleState === "closed" ||
|
|
528
|
-
this._lifecycleState === "disposing" ||
|
|
529
|
-
this._lifecycleState === "disposed"
|
|
526
|
+
this._lifecycleState === "closing" || this._lifecycleState === "closed" || this.disposed
|
|
530
527
|
);
|
|
531
528
|
}
|
|
532
529
|
|
|
530
|
+
public get disposed(): boolean {
|
|
531
|
+
return this._lifecycleState === "disposing" || this._lifecycleState === "disposed";
|
|
532
|
+
}
|
|
533
|
+
|
|
533
534
|
private _attachState = AttachState.Detached;
|
|
534
535
|
|
|
535
536
|
private readonly storageAdapter: ContainerStorageAdapter;
|
|
@@ -556,7 +557,6 @@ export class Container
|
|
|
556
557
|
private inboundQueuePausedFromInit = true;
|
|
557
558
|
private firstConnection = true;
|
|
558
559
|
private readonly connectionTransitionTimes: number[] = [];
|
|
559
|
-
private messageCountAfterDisconnection: number = 0;
|
|
560
560
|
private _loadedFromVersion: IVersion | undefined;
|
|
561
561
|
private attachStarted = false;
|
|
562
562
|
private _dirtyContainer = false;
|
|
@@ -769,42 +769,45 @@ export class Container
|
|
|
769
769
|
}`;
|
|
770
770
|
// Need to use the property getter for docId because for detached flow we don't have the docId initially.
|
|
771
771
|
// We assign the id later so property getter is used.
|
|
772
|
-
this.subLogger =
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
//
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
this.deltaManager?.lastMessage?.
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
772
|
+
this.subLogger = createChildLogger({
|
|
773
|
+
logger: subLogger,
|
|
774
|
+
properties: {
|
|
775
|
+
all: {
|
|
776
|
+
clientType, // Differentiating summarizer container from main container
|
|
777
|
+
containerId: uuid(),
|
|
778
|
+
docId: () => this.resolvedUrl?.id,
|
|
779
|
+
containerAttachState: () => this._attachState,
|
|
780
|
+
containerLifecycleState: () => this._lifecycleState,
|
|
781
|
+
containerConnectionState: () => ConnectionState[this.connectionState],
|
|
782
|
+
serializedContainer: pendingLocalState !== undefined,
|
|
783
|
+
},
|
|
784
|
+
// we need to be judicious with our logging here to avoid generating too much data
|
|
785
|
+
// all data logged here should be broadly applicable, and not specific to a
|
|
786
|
+
// specific error or class of errors
|
|
787
|
+
error: {
|
|
788
|
+
// load information to associate errors with the specific load point
|
|
789
|
+
dmInitialSeqNumber: () => this._deltaManager?.initialSequenceNumber,
|
|
790
|
+
dmLastProcessedSeqNumber: () => this._deltaManager?.lastSequenceNumber,
|
|
791
|
+
dmLastKnownSeqNumber: () => this._deltaManager?.lastKnownSeqNumber,
|
|
792
|
+
containerLoadedFromVersionId: () => this._loadedFromVersion?.id,
|
|
793
|
+
containerLoadedFromVersionDate: () => this._loadedFromVersion?.date,
|
|
794
|
+
// message information to associate errors with the specific execution state
|
|
795
|
+
// dmLastMsqSeqNumber: if present, same as dmLastProcessedSeqNumber
|
|
796
|
+
dmLastMsqSeqNumber: () => this.deltaManager?.lastMessage?.sequenceNumber,
|
|
797
|
+
dmLastMsqSeqTimestamp: () => this.deltaManager?.lastMessage?.timestamp,
|
|
798
|
+
dmLastMsqSeqClientId: () =>
|
|
799
|
+
this.deltaManager?.lastMessage?.clientId === null
|
|
800
|
+
? "null"
|
|
801
|
+
: this.deltaManager?.lastMessage?.clientId,
|
|
802
|
+
dmLastMsgClientSeq: () => this.deltaManager?.lastMessage?.clientSequenceNumber,
|
|
803
|
+
connectionStateDuration: () =>
|
|
804
|
+
performance.now() - this.connectionTransitionTimes[this.connectionState],
|
|
805
|
+
},
|
|
803
806
|
},
|
|
804
807
|
});
|
|
805
808
|
|
|
806
809
|
// Prefix all events in this file with container-loader
|
|
807
|
-
this.mc =
|
|
810
|
+
this.mc = createChildMonitoringContext({ logger: this.subLogger, namespace: "Container" });
|
|
808
811
|
|
|
809
812
|
this._deltaManager = this.createDeltaManager();
|
|
810
813
|
|
|
@@ -900,8 +903,8 @@ export class Container
|
|
|
900
903
|
document !== null &&
|
|
901
904
|
typeof document.addEventListener === "function" &&
|
|
902
905
|
document.addEventListener !== null;
|
|
903
|
-
// keep track of last time page was visible for telemetry
|
|
904
|
-
if (isDomAvailable) {
|
|
906
|
+
// keep track of last time page was visible for telemetry (on interactive clients only)
|
|
907
|
+
if (isDomAvailable && interactive) {
|
|
905
908
|
this.lastVisible = document.hidden ? performance.now() : undefined;
|
|
906
909
|
this.visibilityEventHandler = () => {
|
|
907
910
|
if (document.hidden) {
|
|
@@ -1565,8 +1568,7 @@ export class Container
|
|
|
1565
1568
|
await this.initializeProtocolStateFromSnapshot(attributes, this.storageAdapter, snapshot);
|
|
1566
1569
|
|
|
1567
1570
|
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1568
|
-
await this.
|
|
1569
|
-
true, // existing
|
|
1571
|
+
await this.instantiateRuntime(
|
|
1570
1572
|
codeDetails,
|
|
1571
1573
|
snapshot,
|
|
1572
1574
|
pendingLocalState?.pendingRuntimeState,
|
|
@@ -1654,7 +1656,7 @@ export class Container
|
|
|
1654
1656
|
};
|
|
1655
1657
|
}
|
|
1656
1658
|
|
|
1657
|
-
private async createDetached(
|
|
1659
|
+
private async createDetached(codeDetails: IFluidCodeDetails) {
|
|
1658
1660
|
const attributes: IDocumentAttributes = {
|
|
1659
1661
|
sequenceNumber: detachedContainerRefSeqNumber,
|
|
1660
1662
|
term: OnlyValidTermValue,
|
|
@@ -1664,7 +1666,7 @@ export class Container
|
|
|
1664
1666
|
await this.attachDeltaManagerOpHandler(attributes);
|
|
1665
1667
|
|
|
1666
1668
|
// Need to just seed the source data in the code quorum. Quorum itself is empty
|
|
1667
|
-
const qValues = initQuorumValuesFromCodeDetails(
|
|
1669
|
+
const qValues = initQuorumValuesFromCodeDetails(codeDetails);
|
|
1668
1670
|
this.initializeProtocolState(
|
|
1669
1671
|
attributes,
|
|
1670
1672
|
{
|
|
@@ -1674,10 +1676,7 @@ export class Container
|
|
|
1674
1676
|
}, // IQuorumSnapShot
|
|
1675
1677
|
);
|
|
1676
1678
|
|
|
1677
|
-
|
|
1678
|
-
await this.instantiateContextDetached(
|
|
1679
|
-
false, // existing
|
|
1680
|
-
);
|
|
1679
|
+
await this.instantiateRuntime(codeDetails, undefined);
|
|
1681
1680
|
|
|
1682
1681
|
this.setLoaded();
|
|
1683
1682
|
}
|
|
@@ -1703,21 +1702,17 @@ export class Container
|
|
|
1703
1702
|
this.storageAdapter,
|
|
1704
1703
|
baseTree.blobs.quorumValues,
|
|
1705
1704
|
);
|
|
1706
|
-
const codeDetails = getCodeDetailsFromQuorumValues(qValues);
|
|
1707
1705
|
this.initializeProtocolState(
|
|
1708
1706
|
attributes,
|
|
1709
1707
|
{
|
|
1710
1708
|
members: [],
|
|
1711
1709
|
proposals: [],
|
|
1712
|
-
values:
|
|
1713
|
-
codeDetails !== undefined ? initQuorumValuesFromCodeDetails(codeDetails) : [],
|
|
1710
|
+
values: qValues,
|
|
1714
1711
|
}, // IQuorumSnapShot
|
|
1715
1712
|
);
|
|
1713
|
+
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
1716
1714
|
|
|
1717
|
-
await this.
|
|
1718
|
-
true, // existing
|
|
1719
|
-
snapshotTree,
|
|
1720
|
-
);
|
|
1715
|
+
await this.instantiateRuntime(codeDetails, snapshotTree);
|
|
1721
1716
|
|
|
1722
1717
|
this.setLoaded();
|
|
1723
1718
|
}
|
|
@@ -1786,7 +1781,10 @@ export class Container
|
|
|
1786
1781
|
this.submitMessage(MessageType.Propose, JSON.stringify({ key, value })),
|
|
1787
1782
|
);
|
|
1788
1783
|
|
|
1789
|
-
const protocolLogger =
|
|
1784
|
+
const protocolLogger = createChildLogger({
|
|
1785
|
+
logger: this.subLogger,
|
|
1786
|
+
namespace: "ProtocolHandler",
|
|
1787
|
+
});
|
|
1790
1788
|
|
|
1791
1789
|
protocol.quorum.on("error", (error) => {
|
|
1792
1790
|
protocolLogger.sendErrorEvent(error);
|
|
@@ -1897,7 +1895,7 @@ export class Container
|
|
|
1897
1895
|
const serviceProvider = () => this.service;
|
|
1898
1896
|
const deltaManager = new DeltaManager<ConnectionManager>(
|
|
1899
1897
|
serviceProvider,
|
|
1900
|
-
|
|
1898
|
+
createChildLogger({ logger: this.subLogger, namespace: "DeltaManager" }),
|
|
1901
1899
|
() => this.activeConnection(),
|
|
1902
1900
|
(props: IConnectionManagerFactoryArgs) =>
|
|
1903
1901
|
new ConnectionManager(
|
|
@@ -1905,7 +1903,7 @@ export class Container
|
|
|
1905
1903
|
() => this.isDirty,
|
|
1906
1904
|
this.client,
|
|
1907
1905
|
this._canReconnect,
|
|
1908
|
-
|
|
1906
|
+
createChildLogger({ logger: this.subLogger, namespace: "ConnectionManager" }),
|
|
1909
1907
|
props,
|
|
1910
1908
|
),
|
|
1911
1909
|
);
|
|
@@ -2004,7 +2002,7 @@ export class Container
|
|
|
2004
2002
|
if (value === ConnectionState.Connected) {
|
|
2005
2003
|
durationFromDisconnected =
|
|
2006
2004
|
time - this.connectionTransitionTimes[ConnectionState.Disconnected];
|
|
2007
|
-
durationFromDisconnected =
|
|
2005
|
+
durationFromDisconnected = formatTick(durationFromDisconnected);
|
|
2008
2006
|
} else if (value === ConnectionState.CatchingUp) {
|
|
2009
2007
|
// This info is of most interesting while Catching Up.
|
|
2010
2008
|
checkpointSequenceNumber = this.deltaManager.lastKnownSeqNumber;
|
|
@@ -2038,6 +2036,7 @@ export class Container
|
|
|
2038
2036
|
: undefined,
|
|
2039
2037
|
checkpointSequenceNumber,
|
|
2040
2038
|
quorumSize: this._protocolHandler?.quorum.getMembers().size,
|
|
2039
|
+
isDirty: this.isDirty,
|
|
2041
2040
|
...this._deltaManager.connectionProps,
|
|
2042
2041
|
},
|
|
2043
2042
|
error,
|
|
@@ -2061,26 +2060,11 @@ export class Container
|
|
|
2061
2060
|
}
|
|
2062
2061
|
const state = this.connectionState === ConnectionState.Connected;
|
|
2063
2062
|
|
|
2064
|
-
const logOpsOnReconnect: boolean =
|
|
2065
|
-
this.connectionState === ConnectionState.Connected &&
|
|
2066
|
-
!this.firstConnection &&
|
|
2067
|
-
this.connectionMode === "write";
|
|
2068
|
-
if (logOpsOnReconnect) {
|
|
2069
|
-
this.messageCountAfterDisconnection = 0;
|
|
2070
|
-
}
|
|
2071
|
-
|
|
2072
2063
|
// Both protocol and context should not be undefined if we got so far.
|
|
2073
2064
|
|
|
2074
2065
|
this.setContextConnectedState(state, this.readOnlyInfo.readonly ?? false);
|
|
2075
2066
|
this.protocolHandler.setConnectionState(state, this.clientId);
|
|
2076
2067
|
raiseConnectedEvent(this.mc.logger, this, state, this.clientId, disconnectedReason);
|
|
2077
|
-
|
|
2078
|
-
if (logOpsOnReconnect) {
|
|
2079
|
-
this.mc.logger.sendTelemetryEvent({
|
|
2080
|
-
eventName: "OpsSentOnReconnect",
|
|
2081
|
-
count: this.messageCountAfterDisconnection,
|
|
2082
|
-
});
|
|
2083
|
-
}
|
|
2084
2068
|
}
|
|
2085
2069
|
|
|
2086
2070
|
// back-compat: ADO #1385: Remove in the future, summary op should come through submitSummaryMessage()
|
|
@@ -2156,7 +2140,6 @@ export class Container
|
|
|
2156
2140
|
return -1;
|
|
2157
2141
|
}
|
|
2158
2142
|
|
|
2159
|
-
this.messageCountAfterDisconnection += 1;
|
|
2160
2143
|
this.noopHeuristic?.notifyMessageSent();
|
|
2161
2144
|
return this._deltaManager.submit(
|
|
2162
2145
|
type,
|
|
@@ -2280,17 +2263,7 @@ export class Container
|
|
|
2280
2263
|
return { snapshot, versionId: version?.id };
|
|
2281
2264
|
}
|
|
2282
2265
|
|
|
2283
|
-
private async
|
|
2284
|
-
const codeDetails = this.getCodeDetailsFromQuorum();
|
|
2285
|
-
if (codeDetails === undefined) {
|
|
2286
|
-
throw new Error("pkg should be provided in create flow!!");
|
|
2287
|
-
}
|
|
2288
|
-
|
|
2289
|
-
await this.instantiateContext(existing, codeDetails, snapshot);
|
|
2290
|
-
}
|
|
2291
|
-
|
|
2292
|
-
private async instantiateContext(
|
|
2293
|
-
existing: boolean,
|
|
2266
|
+
private async instantiateRuntime(
|
|
2294
2267
|
codeDetails: IFluidCodeDetails,
|
|
2295
2268
|
snapshot: ISnapshotTree | undefined,
|
|
2296
2269
|
pendingLocalState?: unknown,
|
|
@@ -2327,6 +2300,8 @@ export class Container
|
|
|
2327
2300
|
(this.protocolHandler.quorum.get("code") ??
|
|
2328
2301
|
this.protocolHandler.quorum.get("code2")) as IFluidCodeDetails | undefined;
|
|
2329
2302
|
|
|
2303
|
+
const existing = snapshot !== undefined;
|
|
2304
|
+
|
|
2330
2305
|
const context = new ContainerContext(
|
|
2331
2306
|
this.options,
|
|
2332
2307
|
this.scope,
|
|
@@ -2371,8 +2346,6 @@ export class Container
|
|
|
2371
2346
|
this._lifecycleEvents.emit("runtimeInstantiated");
|
|
2372
2347
|
|
|
2373
2348
|
this._loadedCodeDetails = codeDetails;
|
|
2374
|
-
|
|
2375
|
-
this.emit("contextChanged", codeDetails);
|
|
2376
2349
|
}
|
|
2377
2350
|
|
|
2378
2351
|
private readonly updateDirtyContainerState = (dirty: boolean) => {
|
|
@@ -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 "@fluidframework/common-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,7 +3,6 @@
|
|
|
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
7
|
import { IEventProvider } from "@fluidframework/common-definitions";
|
|
9
8
|
import { ITelemetryProperties, ITelemetryErrorEvent } from "@fluidframework/core-interfaces";
|
|
@@ -93,6 +92,17 @@ function isClientMessage(message: ISequencedDocumentMessage | IDocumentMessage):
|
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Type is used to cast AbortController to represent new version of DOM API and prevent build issues
|
|
97
|
+
* TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
98
|
+
*/
|
|
99
|
+
type AbortControllerReal = AbortController & { abort(reason?: any): void };
|
|
100
|
+
/**
|
|
101
|
+
* Type is used to cast AbortSignal to represent new version of DOM API and prevent build issues
|
|
102
|
+
* TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
103
|
+
*/
|
|
104
|
+
type AbortSignalReal = AbortSignal & { reason: any };
|
|
105
|
+
|
|
96
106
|
/**
|
|
97
107
|
* Manages the flow of both inbound and outbound messages. This class ensures that shared objects receive delta
|
|
98
108
|
* messages in order regardless of possible network conditions or timings causing out of order delivery.
|
|
@@ -624,7 +634,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
624
634
|
// This is useless for known ranges (to is defined) as it means request is over either way.
|
|
625
635
|
// And it will cancel unbound request too early, not allowing us to learn where the end of the file is.
|
|
626
636
|
if (!opsFromFetch && cancelFetch(op)) {
|
|
627
|
-
|
|
637
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
638
|
+
(controller as AbortControllerReal).abort("DeltaManager getDeltas fetch cancelled");
|
|
628
639
|
this._inbound.off("push", opListener);
|
|
629
640
|
}
|
|
630
641
|
};
|
|
@@ -632,7 +643,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
632
643
|
try {
|
|
633
644
|
this._inbound.on("push", opListener);
|
|
634
645
|
assert(this.closeAbortController.signal.onabort === null, 0x1e8 /* "reentrancy" */);
|
|
635
|
-
this.closeAbortController.signal.onabort = () =>
|
|
646
|
+
this.closeAbortController.signal.onabort = () =>
|
|
647
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
648
|
+
(controller as AbortControllerReal).abort(
|
|
649
|
+
(this.closeAbortController.signal as AbortSignalReal).reason,
|
|
650
|
+
);
|
|
636
651
|
|
|
637
652
|
const stream = this.deltaStorage.fetchMessages(
|
|
638
653
|
from, // inclusive
|
|
@@ -656,6 +671,14 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
656
671
|
}
|
|
657
672
|
}
|
|
658
673
|
} finally {
|
|
674
|
+
if (controller.signal.aborted) {
|
|
675
|
+
this.logger.sendTelemetryEvent({
|
|
676
|
+
eventName: "DeltaManager_GetDeltasAborted",
|
|
677
|
+
fetchReason,
|
|
678
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
679
|
+
reason: (controller.signal as AbortSignalReal).reason,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
659
682
|
this.closeAbortController.signal.onabort = null;
|
|
660
683
|
this._inbound.off("push", opListener);
|
|
661
684
|
assert(!opsFromFetch, 0x289 /* "logic error" */);
|
|
@@ -710,7 +733,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
|
|
|
710
733
|
}
|
|
711
734
|
|
|
712
735
|
private clearQueues() {
|
|
713
|
-
|
|
736
|
+
// TODO: Remove when typescript version of the repo contains the AbortSignal.reason property (AB#5045)
|
|
737
|
+
(this.closeAbortController as AbortControllerReal).abort("DeltaManager is closed");
|
|
714
738
|
|
|
715
739
|
this._inbound.clear();
|
|
716
740
|
this._inboundSignal.clear();
|
package/src/loader.ts
CHANGED
|
@@ -6,14 +6,12 @@
|
|
|
6
6
|
import { v4 as uuid } from "uuid";
|
|
7
7
|
import {
|
|
8
8
|
ITelemetryLoggerExt,
|
|
9
|
-
ChildLogger,
|
|
10
|
-
DebugLogger,
|
|
11
9
|
IConfigProviderBase,
|
|
12
|
-
loggerToMonitoringContext,
|
|
13
10
|
mixinMonitoringContext,
|
|
14
11
|
MonitoringContext,
|
|
15
12
|
PerformanceEvent,
|
|
16
13
|
sessionStorageConfigProvider,
|
|
14
|
+
createChildMonitoringContext,
|
|
17
15
|
} from "@fluidframework/telemetry-utils";
|
|
18
16
|
import {
|
|
19
17
|
ITelemetryBaseLogger,
|
|
@@ -44,6 +42,7 @@ import { Container, IPendingContainerState } from "./container";
|
|
|
44
42
|
import { IParsedUrl, parseUrl } from "./utils";
|
|
45
43
|
import { pkgVersion } from "./packageVersion";
|
|
46
44
|
import { ProtocolHandlerBuilder } from "./protocol";
|
|
45
|
+
import { DebugLogger } from "./debugLogger";
|
|
47
46
|
|
|
48
47
|
function canUseCache(request: IRequest): boolean {
|
|
49
48
|
if (request.headers === undefined) {
|
|
@@ -343,7 +342,10 @@ export class Loader implements IHostLoader {
|
|
|
343
342
|
protocolHandlerBuilder,
|
|
344
343
|
subLogger: subMc.logger,
|
|
345
344
|
};
|
|
346
|
-
this.mc =
|
|
345
|
+
this.mc = createChildMonitoringContext({
|
|
346
|
+
logger: this.services.subLogger,
|
|
347
|
+
namespace: "Loader",
|
|
348
|
+
});
|
|
347
349
|
}
|
|
348
350
|
|
|
349
351
|
public get IFluidRouter(): IFluidRouter {
|
|
@@ -407,16 +409,23 @@ export class Loader implements IHostLoader {
|
|
|
407
409
|
this.containers.set(key, containerP);
|
|
408
410
|
containerP
|
|
409
411
|
.then((container) => {
|
|
410
|
-
// If the container is closed or becomes closed after we resolve it,
|
|
411
|
-
|
|
412
|
+
// If the container is closed/disposed or becomes closed/disposed after we resolve it,
|
|
413
|
+
// remove it from the cache.
|
|
414
|
+
if (container.closed || container.disposed) {
|
|
412
415
|
this.containers.delete(key);
|
|
413
416
|
} else {
|
|
414
417
|
container.once("closed", () => {
|
|
415
418
|
this.containers.delete(key);
|
|
416
419
|
});
|
|
420
|
+
container.once("disposed", () => {
|
|
421
|
+
this.containers.delete(key);
|
|
422
|
+
});
|
|
417
423
|
}
|
|
418
424
|
})
|
|
419
|
-
.catch((error) => {
|
|
425
|
+
.catch((error) => {
|
|
426
|
+
// If an error occured while resolving the container request, then remove it from the cache.
|
|
427
|
+
this.containers.delete(key);
|
|
428
|
+
});
|
|
420
429
|
}
|
|
421
430
|
|
|
422
431
|
private async resolveCore(
|
package/src/packageVersion.ts
CHANGED
package/src/quorum.ts
CHANGED
|
@@ -2,19 +2,9 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { assert } from "@fluidframework/common-utils";
|
|
6
5
|
import { IFluidCodeDetails } from "@fluidframework/core-interfaces";
|
|
7
6
|
import { ICommittedProposal } from "@fluidframework/protocol-definitions";
|
|
8
7
|
|
|
9
|
-
export function getCodeDetailsFromQuorumValues(
|
|
10
|
-
quorumValues: [string, ICommittedProposal][],
|
|
11
|
-
): IFluidCodeDetails {
|
|
12
|
-
const qValuesMap = new Map(quorumValues);
|
|
13
|
-
const proposal = qValuesMap.get("code");
|
|
14
|
-
assert(proposal !== undefined, 0x2dc /* "Cannot find code proposal" */);
|
|
15
|
-
return proposal?.value as IFluidCodeDetails;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
8
|
export function initQuorumValuesFromCodeDetails(
|
|
19
9
|
source: IFluidCodeDetails,
|
|
20
10
|
): [string, ICommittedProposal][] {
|