@fluidframework/container-loader 2.0.0-internal.4.3.1 → 2.0.0-internal.4.4.1

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/connectionManager.d.ts +2 -1
  3. package/dist/connectionManager.d.ts.map +1 -1
  4. package/dist/connectionManager.js +19 -15
  5. package/dist/connectionManager.js.map +1 -1
  6. package/dist/connectionStateHandler.d.ts +7 -6
  7. package/dist/connectionStateHandler.d.ts.map +1 -1
  8. package/dist/connectionStateHandler.js +11 -11
  9. package/dist/connectionStateHandler.js.map +1 -1
  10. package/dist/container.d.ts.map +1 -1
  11. package/dist/container.js +8 -6
  12. package/dist/container.js.map +1 -1
  13. package/dist/contracts.d.ts +3 -3
  14. package/dist/contracts.d.ts.map +1 -1
  15. package/dist/contracts.js.map +1 -1
  16. package/dist/deltaManager.d.ts.map +1 -1
  17. package/dist/deltaManager.js +4 -4
  18. package/dist/deltaManager.js.map +1 -1
  19. package/dist/packageVersion.d.ts +1 -1
  20. package/dist/packageVersion.js +1 -1
  21. package/dist/packageVersion.js.map +1 -1
  22. package/lib/connectionManager.d.ts +2 -1
  23. package/lib/connectionManager.d.ts.map +1 -1
  24. package/lib/connectionManager.js +19 -15
  25. package/lib/connectionManager.js.map +1 -1
  26. package/lib/connectionStateHandler.d.ts +7 -6
  27. package/lib/connectionStateHandler.d.ts.map +1 -1
  28. package/lib/connectionStateHandler.js +11 -11
  29. package/lib/connectionStateHandler.js.map +1 -1
  30. package/lib/container.d.ts.map +1 -1
  31. package/lib/container.js +8 -6
  32. package/lib/container.js.map +1 -1
  33. package/lib/contracts.d.ts +3 -3
  34. package/lib/contracts.d.ts.map +1 -1
  35. package/lib/contracts.js.map +1 -1
  36. package/lib/deltaManager.d.ts.map +1 -1
  37. package/lib/deltaManager.js +4 -4
  38. package/lib/deltaManager.js.map +1 -1
  39. package/lib/packageVersion.d.ts +1 -1
  40. package/lib/packageVersion.js +1 -1
  41. package/lib/packageVersion.js.map +1 -1
  42. package/package.json +9 -9
  43. package/src/connectionManager.ts +22 -13
  44. package/src/connectionStateHandler.ts +19 -10
  45. package/src/container.ts +29 -22
  46. package/src/contracts.ts +3 -3
  47. package/src/deltaManager.ts +6 -4
  48. package/src/packageVersion.ts +1 -1
@@ -325,6 +325,7 @@ export class ConnectionManager implements IConnectionManager {
325
325
 
326
326
  private static detailsFromConnection(
327
327
  connection: IDocumentDeltaConnection,
328
+ reason: string,
328
329
  ): IConnectionDetailsInternal {
329
330
  return {
330
331
  claims: connection.claims,
@@ -336,6 +337,7 @@ export class ConnectionManager implements IConnectionManager {
336
337
  mode: connection.mode,
337
338
  serviceConfiguration: connection.serviceConfiguration,
338
339
  version: connection.version,
340
+ reason,
339
341
  };
340
342
  }
341
343
 
@@ -457,7 +459,7 @@ export class ConnectionManager implements IConnectionManager {
457
459
  this.props.readonlyChangeHandler(this.readonly);
458
460
  if (reconnect) {
459
461
  // reconnect if we disconnected from before.
460
- this.triggerConnect("read");
462
+ this.triggerConnect("Force Readonly", "read");
461
463
  }
462
464
  }
463
465
  }
@@ -470,14 +472,14 @@ export class ConnectionManager implements IConnectionManager {
470
472
  }
471
473
  }
472
474
 
473
- public connect(connectionMode?: ConnectionMode) {
474
- this.connectCore(connectionMode).catch((error) => {
475
+ public connect(reason: string, connectionMode?: ConnectionMode) {
476
+ this.connectCore(reason, connectionMode).catch((error) => {
475
477
  const normalizedError = normalizeError(error, { props: fatalConnectErrorProp });
476
478
  this.props.closeHandler(normalizedError);
477
479
  });
478
480
  }
479
481
 
480
- private async connectCore(connectionMode?: ConnectionMode): Promise<void> {
482
+ private async connectCore(reason: string, connectionMode?: ConnectionMode): Promise<void> {
481
483
  assert(!this._disposed, 0x26a /* "not closed" */);
482
484
 
483
485
  if (this.connection !== undefined) {
@@ -512,7 +514,7 @@ export class ConnectionManager implements IConnectionManager {
512
514
 
513
515
  if (docService.policies?.storageOnly === true) {
514
516
  connection = new NoDeltaStream();
515
- this.setupNewSuccessfulConnection(connection, "read");
517
+ this.setupNewSuccessfulConnection(connection, "read", reason);
516
518
  assert(this.pendingConnection === undefined, 0x2b3 /* "logic error" */);
517
519
  return;
518
520
  }
@@ -639,7 +641,7 @@ export class ConnectionManager implements IConnectionManager {
639
641
  return;
640
642
  }
641
643
 
642
- this.setupNewSuccessfulConnection(connection, requestedMode);
644
+ this.setupNewSuccessfulConnection(connection, requestedMode, reason);
643
645
  }
644
646
 
645
647
  /**
@@ -647,7 +649,7 @@ export class ConnectionManager implements IConnectionManager {
647
649
  * And report the error if it escapes for any reason.
648
650
  * @param args - The connection arguments
649
651
  */
650
- private triggerConnect(connectionMode: ConnectionMode) {
652
+ private triggerConnect(reason: string, connectionMode: ConnectionMode) {
651
653
  // reconnect() includes async awaits, and that causes potential race conditions
652
654
  // where we might already have a connection. If it were to happen, it's possible that we will connect
653
655
  // with different mode to `connectionMode`. Glancing through the caller chains, it looks like code should be
@@ -658,15 +660,16 @@ export class ConnectionManager implements IConnectionManager {
658
660
  if (this.reconnectMode !== ReconnectMode.Enabled) {
659
661
  return;
660
662
  }
661
- this.connect(connectionMode);
663
+ this.connect(reason, connectionMode);
662
664
  }
663
665
 
664
666
  /**
665
667
  * Disconnect the current connection.
666
668
  * @param reason - Text description of disconnect reason to emit with disconnect event
669
+ * @param error - Error causing the disconnect if any.
667
670
  * @returns A boolean that indicates if there was an existing connection (or pending connection) to disconnect
668
671
  */
669
- private disconnectFromDeltaStream(reason: string): boolean {
672
+ private disconnectFromDeltaStream(reason: string, error?: IAnyDriverError): boolean {
670
673
  this.pendingReconnect = false;
671
674
 
672
675
  if (this.connection === undefined) {
@@ -699,7 +702,7 @@ export class ConnectionManager implements IConnectionManager {
699
702
  this._outbound.clear();
700
703
  connection.dispose();
701
704
 
702
- this.props.disconnectHandler(reason);
705
+ this.props.disconnectHandler(reason, error);
703
706
 
704
707
  this._connectionVerboseProps = {};
705
708
 
@@ -727,6 +730,7 @@ export class ConnectionManager implements IConnectionManager {
727
730
  private setupNewSuccessfulConnection(
728
731
  connection: IDocumentDeltaConnection,
729
732
  requestedMode: ConnectionMode,
733
+ reason: string,
730
734
  ) {
731
735
  // Old connection should have been cleaned up before establishing a new one
732
736
  assert(
@@ -827,7 +831,7 @@ export class ConnectionManager implements IConnectionManager {
827
831
  this.connectFirstConnection ? "InitialOps" : "ReconnectOps",
828
832
  );
829
833
 
830
- const details = ConnectionManager.detailsFromConnection(connection);
834
+ const details = ConnectionManager.detailsFromConnection(connection, reason);
831
835
  details.checkpointSequenceNumber = checkpointSequenceNumber;
832
836
  this.props.connectHandler(details);
833
837
 
@@ -894,7 +898,7 @@ export class ConnectionManager implements IConnectionManager {
894
898
  // If we're already disconnected/disconnecting it's not appropriate to call this again.
895
899
  assert(this.connection !== undefined, 0x0eb /* "Missing connection for reconnect" */);
896
900
 
897
- this.disconnectFromDeltaStream(disconnectMessage);
901
+ this.disconnectFromDeltaStream(disconnectMessage, error);
898
902
 
899
903
  // We will always trigger reconnect, even if canRetry is false.
900
904
  // Any truly fatal error state will result in container close upon attempted reconnect,
@@ -935,7 +939,12 @@ export class ConnectionManager implements IConnectionManager {
935
939
  // should probably live in the driver.
936
940
  await waitForOnline();
937
941
 
938
- this.triggerConnect(requestedMode);
942
+ this.triggerConnect(
943
+ error !== undefined
944
+ ? "Reconnect on Error"
945
+ : `Reconnecting due to: ${disconnectMessage}`,
946
+ requestedMode,
947
+ );
939
948
  }
940
949
 
941
950
  public prepareMessageToSend(
@@ -10,6 +10,7 @@ import {
10
10
  } from "@fluidframework/common-definitions";
11
11
  import { assert, Timer } from "@fluidframework/common-utils";
12
12
  import { IConnectionDetailsInternal, IDeltaManager } from "@fluidframework/container-definitions";
13
+ import { IAnyDriverError } from "@fluidframework/driver-definitions";
13
14
  import { ISequencedClient, IClient } from "@fluidframework/protocol-definitions";
14
15
  import { PerformanceEvent, loggerToMonitoringContext } from "@fluidframework/telemetry-utils";
15
16
  import { ConnectionState } from "./connectionState";
@@ -32,6 +33,7 @@ export interface IConnectionStateHandlerInputs {
32
33
  value: ConnectionState,
33
34
  oldState: ConnectionState,
34
35
  reason?: string | undefined,
36
+ error?: IAnyDriverError,
35
37
  ) => void;
36
38
  /** Whether to expect the client to join in write mode on next connection */
37
39
  shouldClientJoinWrite: () => boolean;
@@ -56,7 +58,7 @@ export interface IConnectionStateHandler {
56
58
  dispose(): void;
57
59
  initProtocol(protocol: IProtocolHandler): void;
58
60
  receivedConnectEvent(details: IConnectionDetailsInternal): void;
59
- receivedDisconnectEvent(reason: string): void;
61
+ receivedDisconnectEvent(reason: string, error?: IAnyDriverError): void;
60
62
  }
61
63
 
62
64
  export function createConnectionStateHandler(
@@ -138,8 +140,8 @@ class ConnectionStateHandlerPassThrough
138
140
  public initProtocol(protocol: IProtocolHandler) {
139
141
  return this.pimpl.initProtocol(protocol);
140
142
  }
141
- public receivedDisconnectEvent(reason: string) {
142
- return this.pimpl.receivedDisconnectEvent(reason);
143
+ public receivedDisconnectEvent(reason: string, error?: IAnyDriverError) {
144
+ return this.pimpl.receivedDisconnectEvent(reason, error);
143
145
  }
144
146
 
145
147
  public receivedConnectEvent(details: IConnectionDetailsInternal) {
@@ -157,8 +159,9 @@ class ConnectionStateHandlerPassThrough
157
159
  value: ConnectionState,
158
160
  oldState: ConnectionState,
159
161
  reason?: string | undefined,
162
+ error?: IAnyDriverError,
160
163
  ) {
161
- return this.inputs.connectionStateChanged(value, oldState, reason);
164
+ return this.inputs.connectionStateChanged(value, oldState, reason, error);
162
165
  }
163
166
  public shouldClientJoinWrite() {
164
167
  return this.inputs.shouldClientJoinWrite();
@@ -200,6 +203,7 @@ class ConnectionStateCatchup extends ConnectionStateHandlerPassThrough {
200
203
  value: ConnectionState,
201
204
  oldState: ConnectionState,
202
205
  reason?: string | undefined,
206
+ error?: IAnyDriverError,
203
207
  ) {
204
208
  switch (value) {
205
209
  case ConnectionState.Connected:
@@ -235,7 +239,7 @@ class ConnectionStateCatchup extends ConnectionStateHandlerPassThrough {
235
239
  default:
236
240
  }
237
241
  this._connectionState = value;
238
- this.inputs.connectionStateChanged(value, oldState, reason);
242
+ this.inputs.connectionStateChanged(value, oldState, reason, error);
239
243
  }
240
244
 
241
245
  private readonly transitionToConnectedState = () => {
@@ -462,9 +466,9 @@ class ConnectionStateHandler implements IConnectionStateHandler {
462
466
  }
463
467
  }
464
468
 
465
- public receivedDisconnectEvent(reason: string) {
469
+ public receivedDisconnectEvent(reason: string, error?: IAnyDriverError) {
466
470
  this.connection = undefined;
467
- this.setConnectionState(ConnectionState.Disconnected, reason);
471
+ this.setConnectionState(ConnectionState.Disconnected, reason, error);
468
472
  }
469
473
 
470
474
  private shouldWaitForJoinSignal() {
@@ -507,7 +511,7 @@ class ConnectionStateHandler implements IConnectionStateHandler {
507
511
  this._pendingClientId = details.clientId;
508
512
 
509
513
  // IMPORTANT: Report telemetry after we set _pendingClientId, but before transitioning to Connected state
510
- this.handler.connectionStateChanged(ConnectionState.CatchingUp, oldState);
514
+ this.handler.connectionStateChanged(ConnectionState.CatchingUp, oldState, details.reason);
511
515
 
512
516
  // Check if we need to wait for join op/signal, and if we need to wait for leave op from previous connection.
513
517
  // Pending clientId could have joined already (i.e. join op/signal already processed):
@@ -527,11 +531,16 @@ class ConnectionStateHandler implements IConnectionStateHandler {
527
531
  // else - We are waiting for Leave op still, do nothing for now, we will transition to Connected later
528
532
  }
529
533
 
530
- private setConnectionState(value: ConnectionState.Disconnected, reason: string): void;
534
+ private setConnectionState(
535
+ value: ConnectionState.Disconnected,
536
+ reason: string,
537
+ error?: IAnyDriverError,
538
+ ): void;
531
539
  private setConnectionState(value: ConnectionState.Connected): void;
532
540
  private setConnectionState(
533
541
  value: ConnectionState.Disconnected | ConnectionState.Connected,
534
542
  reason?: string,
543
+ error?: IAnyDriverError,
535
544
  ): void {
536
545
  if (this.connectionState === value) {
537
546
  // Already in the desired state - exit early
@@ -592,7 +601,7 @@ class ConnectionStateHandler implements IConnectionStateHandler {
592
601
  }
593
602
 
594
603
  // Report transition before we propagate event across layers
595
- this.handler.connectionStateChanged(this._connectionState, oldState, reason);
604
+ this.handler.connectionStateChanged(this._connectionState, oldState, reason, error);
596
605
  }
597
606
 
598
607
  // Helper method to switch between quorum and audience.
package/src/container.ts CHANGED
@@ -32,6 +32,7 @@ import {
32
32
  } from "@fluidframework/container-definitions";
33
33
  import { GenericError, UsageError } from "@fluidframework/container-utils";
34
34
  import {
35
+ IAnyDriverError,
35
36
  IDocumentService,
36
37
  IDocumentStorageService,
37
38
  IFluidResolvedUrl,
@@ -758,11 +759,11 @@ export class Container
758
759
  this.connectionStateHandler = createConnectionStateHandler(
759
760
  {
760
761
  logger: this.mc.logger,
761
- connectionStateChanged: (value, oldState, reason) => {
762
+ connectionStateChanged: (value, oldState, reason, error) => {
762
763
  if (value === ConnectionState.Connected) {
763
764
  this._clientId = this.connectionStateHandler.pendingClientId;
764
765
  }
765
- this.logConnectionStateChangeTelemetry(value, oldState, reason);
766
+ this.logConnectionStateChangeTelemetry(value, oldState, reason, error);
766
767
  if (this._lifecycleState === "loaded") {
767
768
  this.propagateConnectionState(
768
769
  false /* initial transition */,
@@ -1843,10 +1844,10 @@ export class Container
1843
1844
  this.connectionStateHandler.receivedConnectEvent(details);
1844
1845
  });
1845
1846
 
1846
- deltaManager.on("disconnect", (reason: string) => {
1847
+ deltaManager.on("disconnect", (reason: string, error?: IAnyDriverError) => {
1847
1848
  this.collabWindowTracker?.stopSequenceNumberUpdate();
1848
1849
  if (!this.closed) {
1849
- this.connectionStateHandler.receivedDisconnectEvent(reason);
1850
+ this.connectionStateHandler.receivedDisconnectEvent(reason, error);
1850
1851
  }
1851
1852
  });
1852
1853
 
@@ -1900,6 +1901,7 @@ export class Container
1900
1901
  value: ConnectionState,
1901
1902
  oldState: ConnectionState,
1902
1903
  reason?: string,
1904
+ error?: IAnyDriverError,
1903
1905
  ) {
1904
1906
  // Log actual event
1905
1907
  const time = performance.now();
@@ -1928,24 +1930,29 @@ export class Container
1928
1930
  connectionInitiationReason = this.firstConnection ? "InitialConnect" : "AutoReconnect";
1929
1931
  }
1930
1932
 
1931
- this.mc.logger.sendPerformanceEvent({
1932
- eventName: `ConnectionStateChange_${ConnectionState[value]}`,
1933
- from: ConnectionState[oldState],
1934
- duration,
1935
- durationFromDisconnected,
1936
- reason,
1937
- connectionInitiationReason,
1938
- pendingClientId: this.connectionStateHandler.pendingClientId,
1939
- clientId: this.clientId,
1940
- autoReconnect,
1941
- opsBehind,
1942
- online: OnlineStatus[isOnline()],
1943
- lastVisible:
1944
- this.lastVisible !== undefined ? performance.now() - this.lastVisible : undefined,
1945
- checkpointSequenceNumber,
1946
- quorumSize: this._protocolHandler?.quorum.getMembers().size,
1947
- ...this._deltaManager.connectionProps,
1948
- });
1933
+ this.mc.logger.sendPerformanceEvent(
1934
+ {
1935
+ eventName: `ConnectionStateChange_${ConnectionState[value]}`,
1936
+ from: ConnectionState[oldState],
1937
+ duration,
1938
+ durationFromDisconnected,
1939
+ reason,
1940
+ connectionInitiationReason,
1941
+ pendingClientId: this.connectionStateHandler.pendingClientId,
1942
+ clientId: this.clientId,
1943
+ autoReconnect,
1944
+ opsBehind,
1945
+ online: OnlineStatus[isOnline()],
1946
+ lastVisible:
1947
+ this.lastVisible !== undefined
1948
+ ? performance.now() - this.lastVisible
1949
+ : undefined,
1950
+ checkpointSequenceNumber,
1951
+ quorumSize: this._protocolHandler?.quorum.getMembers().size,
1952
+ ...this._deltaManager.connectionProps,
1953
+ },
1954
+ error,
1955
+ );
1949
1956
 
1950
1957
  if (value === ConnectionState.Connected) {
1951
1958
  this.firstConnection = false;
package/src/contracts.ts CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  IClientDetails,
21
21
  ISignalMessage,
22
22
  } from "@fluidframework/protocol-definitions";
23
- import { IContainerPackageInfo } from "@fluidframework/driver-definitions";
23
+ import { IAnyDriverError, IContainerPackageInfo } from "@fluidframework/driver-definitions";
24
24
 
25
25
  export enum ReconnectMode {
26
26
  Never = "Never",
@@ -95,7 +95,7 @@ export interface IConnectionManager {
95
95
  /**
96
96
  * Initiates connection to relay service (noop if already connected).
97
97
  */
98
- connect(connectionMode?: ConnectionMode): void;
98
+ connect(reason: string, connectionMode?: ConnectionMode): void;
99
99
 
100
100
  /**
101
101
  * Disposed connection manager
@@ -139,7 +139,7 @@ export interface IConnectionManagerFactoryArgs {
139
139
  /**
140
140
  * Called whenever connection to relay service is lost.
141
141
  */
142
- readonly disconnectHandler: (reason: string) => void;
142
+ readonly disconnectHandler: (reason: string, error?: IAnyDriverError) => void;
143
143
 
144
144
  /**
145
145
  * Called whenever new connection to rely service is established
@@ -26,6 +26,7 @@ import {
26
26
  IDocumentDeltaStorageService,
27
27
  IDocumentService,
28
28
  DriverErrorType,
29
+ IAnyDriverError,
29
30
  } from "@fluidframework/driver-definitions";
30
31
  import {
31
32
  IDocumentMessage,
@@ -357,7 +358,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
357
358
  reconnectionDelayHandler: (delayMs: number, error: unknown) =>
358
359
  this.emitDelayInfo(this.deltaStreamDelayId, delayMs, error),
359
360
  closeHandler: (error: any) => this.close(error),
360
- disconnectHandler: (reason: string) => this.disconnectHandler(reason),
361
+ disconnectHandler: (reason: string, error?: IAnyDriverError) =>
362
+ this.disconnectHandler(reason, error),
361
363
  connectHandler: (connection: IConnectionDetailsInternal) =>
362
364
  this.connectHandler(connection),
363
365
  pongHandler: (latency: number) => this.emit("pong", latency),
@@ -539,7 +541,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
539
541
  this.fetchMissingDeltas(args.reason);
540
542
  }
541
543
 
542
- this.connectionManager.connect(args.mode);
544
+ this.connectionManager.connect(args.reason, args.mode);
543
545
  }
544
546
 
545
547
  private async getDeltas(
@@ -700,9 +702,9 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
700
702
  }
701
703
  }
702
704
 
703
- private disconnectHandler(reason: string) {
705
+ private disconnectHandler(reason: string, error?: IAnyDriverError) {
704
706
  this.messageBuffer.length = 0;
705
- this.emit("disconnect", reason);
707
+ this.emit("disconnect", reason, error);
706
708
  }
707
709
 
708
710
  /**
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "2.0.0-internal.4.3.1";
9
+ export const pkgVersion = "2.0.0-internal.4.4.1";