@fluidframework/container-loader 0.59.4001 → 1.0.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.
Files changed (100) hide show
  1. package/.eslintrc.js +1 -1
  2. package/README.md +1 -1
  3. package/dist/connectionState.d.ts +15 -3
  4. package/dist/connectionState.d.ts.map +1 -1
  5. package/dist/connectionState.js +15 -3
  6. package/dist/connectionState.js.map +1 -1
  7. package/dist/connectionStateHandler.d.ts +6 -4
  8. package/dist/connectionStateHandler.d.ts.map +1 -1
  9. package/dist/connectionStateHandler.js +21 -6
  10. package/dist/connectionStateHandler.js.map +1 -1
  11. package/dist/container.d.ts +18 -26
  12. package/dist/container.d.ts.map +1 -1
  13. package/dist/container.js +54 -88
  14. package/dist/container.js.map +1 -1
  15. package/dist/containerContext.d.ts +6 -4
  16. package/dist/containerContext.d.ts.map +1 -1
  17. package/dist/containerContext.js +8 -7
  18. package/dist/containerContext.js.map +1 -1
  19. package/dist/containerStorageAdapter.d.ts +2 -3
  20. package/dist/containerStorageAdapter.d.ts.map +1 -1
  21. package/dist/containerStorageAdapter.js +0 -3
  22. package/dist/containerStorageAdapter.js.map +1 -1
  23. package/dist/deltaManagerProxy.d.ts +0 -1
  24. package/dist/deltaManagerProxy.d.ts.map +1 -1
  25. package/dist/deltaManagerProxy.js +0 -3
  26. package/dist/deltaManagerProxy.js.map +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/loader.d.ts +1 -13
  31. package/dist/loader.d.ts.map +1 -1
  32. package/dist/loader.js +2 -3
  33. package/dist/loader.js.map +1 -1
  34. package/dist/packageVersion.d.ts +1 -1
  35. package/dist/packageVersion.d.ts.map +1 -1
  36. package/dist/packageVersion.js +1 -1
  37. package/dist/packageVersion.js.map +1 -1
  38. package/dist/protocolTreeDocumentStorageService.d.ts +0 -1
  39. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  40. package/dist/protocolTreeDocumentStorageService.js +0 -1
  41. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  42. package/dist/retriableDocumentStorageService.d.ts +1 -2
  43. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  44. package/dist/retriableDocumentStorageService.js +0 -3
  45. package/dist/retriableDocumentStorageService.js.map +1 -1
  46. package/lib/connectionState.d.ts +15 -3
  47. package/lib/connectionState.d.ts.map +1 -1
  48. package/lib/connectionState.js +15 -3
  49. package/lib/connectionState.js.map +1 -1
  50. package/lib/connectionStateHandler.d.ts +6 -4
  51. package/lib/connectionStateHandler.d.ts.map +1 -1
  52. package/lib/connectionStateHandler.js +21 -6
  53. package/lib/connectionStateHandler.js.map +1 -1
  54. package/lib/container.d.ts +18 -26
  55. package/lib/container.d.ts.map +1 -1
  56. package/lib/container.js +54 -88
  57. package/lib/container.js.map +1 -1
  58. package/lib/containerContext.d.ts +6 -4
  59. package/lib/containerContext.d.ts.map +1 -1
  60. package/lib/containerContext.js +8 -7
  61. package/lib/containerContext.js.map +1 -1
  62. package/lib/containerStorageAdapter.d.ts +2 -3
  63. package/lib/containerStorageAdapter.d.ts.map +1 -1
  64. package/lib/containerStorageAdapter.js +0 -3
  65. package/lib/containerStorageAdapter.js.map +1 -1
  66. package/lib/deltaManagerProxy.d.ts +0 -1
  67. package/lib/deltaManagerProxy.d.ts.map +1 -1
  68. package/lib/deltaManagerProxy.js +0 -3
  69. package/lib/deltaManagerProxy.js.map +1 -1
  70. package/lib/index.d.ts +1 -1
  71. package/lib/index.d.ts.map +1 -1
  72. package/lib/index.js.map +1 -1
  73. package/lib/loader.d.ts +1 -13
  74. package/lib/loader.d.ts.map +1 -1
  75. package/lib/loader.js +2 -3
  76. package/lib/loader.js.map +1 -1
  77. package/lib/packageVersion.d.ts +1 -1
  78. package/lib/packageVersion.d.ts.map +1 -1
  79. package/lib/packageVersion.js +1 -1
  80. package/lib/packageVersion.js.map +1 -1
  81. package/lib/protocolTreeDocumentStorageService.d.ts +0 -1
  82. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  83. package/lib/protocolTreeDocumentStorageService.js +0 -1
  84. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  85. package/lib/retriableDocumentStorageService.d.ts +1 -2
  86. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  87. package/lib/retriableDocumentStorageService.js +0 -3
  88. package/lib/retriableDocumentStorageService.js.map +1 -1
  89. package/package.json +26 -26
  90. package/src/connectionState.ts +20 -6
  91. package/src/connectionStateHandler.ts +29 -8
  92. package/src/container.ts +77 -100
  93. package/src/containerContext.ts +10 -10
  94. package/src/containerStorageAdapter.ts +1 -6
  95. package/src/deltaManagerProxy.ts +0 -4
  96. package/src/index.ts +1 -0
  97. package/src/loader.ts +4 -21
  98. package/src/packageVersion.ts +1 -1
  99. package/src/protocolTreeDocumentStorageService.ts +0 -1
  100. package/src/retriableDocumentStorageService.ts +0 -8
package/.eslintrc.js CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  module.exports = {
7
7
  "extends": [
8
- "@fluidframework/eslint-config-fluid"
8
+ require.resolve("@fluidframework/eslint-config-fluid")
9
9
  ],
10
10
  "parserOptions": {
11
11
  "project": ["./tsconfig.json", "./src/test/tsconfig.json"]
package/README.md CHANGED
@@ -149,7 +149,7 @@ Container will also not attempt to reconnect on lost connection if `Container.di
149
149
 
150
150
  Data stores should almost never listen to these events (see more on [Readonly states](#Readonly-states), and should use consensus DDSes if they need to synchronize activity across clients. DDSes listen for these events to know when to resubmit pending Ops.
151
151
 
152
- Hosting application can use these events in order to indicate to user when user changes are not propagating through the system, and thus can be lost (on browser tab being closed). It's advised to use some delay (like 5 seconds) before showing such UI, as network connectivity might be intermittent. Also if container was offline for very long period of time due to `Container.setAutoReconnect(false)` being called, it might take a while to get connected and current.
152
+ Hosting application can use these events in order to indicate to user when user changes are not propagating through the system, and thus can be lost (on browser tab being closed). It's advised to use some delay (like 5 seconds) before showing such UI, as network connectivity might be intermittent. Also if container was offline for very long period of time due to `Container.disconnect()` being called, it might take a while to get connected and current.
153
153
 
154
154
  Please note that hosts can implement various strategies on how to handle disconnections. Some may decide to show some UX letting user know about potential loss of data if container is closed while disconnected. Others can force container to disallow user edits while offline (see [Readonly states](#Readonly-states)).
155
155
 
@@ -4,15 +4,27 @@
4
4
  */
5
5
  export declare enum ConnectionState {
6
6
  /**
7
- * The document is no longer connected to the delta server
7
+ * The container is not connected to the ordering service
8
+ * Note - When in this state the container may be about to reconnect,
9
+ * or may remain disconnected until explicitly told to connect.
8
10
  */
9
11
  Disconnected = 0,
10
12
  /**
11
- * The document has an inbound connection but is still pending for outbound deltas
13
+ * The container is disconnected but actively trying to establish a new connection
14
+ * PLEASE NOTE that this numerical value falls out of the order you may expect for this state
15
+ */
16
+ EstablishingConnection = 3,
17
+ /**
18
+ * @see ConnectionState.CatchingUp, which is the new name for this state.
19
+ * @deprecated - This state itself is not gone, just being renamed. Please use ConnectionState.CatchingUp.
12
20
  */
13
21
  Connecting = 1,
14
22
  /**
15
- * The document is fully connected
23
+ * The container has an inbound connection only, and is catching up to the latest known state from the service.
24
+ */
25
+ CatchingUp = 1,
26
+ /**
27
+ * The container is fully connected and syncing
16
28
  */
17
29
  Connected = 2
18
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"connectionState.d.ts","sourceRoot":"","sources":["../src/connectionState.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oBAAY,eAAe;IACvB;;OAEG;IACH,YAAY,IAAA;IAEZ;;OAEG;IACH,UAAU,IAAA;IAEV;;OAEG;IACH,SAAS,IAAA;CACZ"}
1
+ {"version":3,"file":"connectionState.d.ts","sourceRoot":"","sources":["../src/connectionState.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oBAAY,eAAe;IACvB;;;;OAIG;IACH,YAAY,IAAI;IAEhB;;;OAGG;IACH,sBAAsB,IAAI;IAE1B;;;OAGG;IACH,UAAU,IAAI;IAEd;;OAEG;IACH,UAAU,IAAI;IAEd;;OAEG;IACH,SAAS,IAAI;CAChB"}
@@ -8,15 +8,27 @@ exports.ConnectionState = void 0;
8
8
  var ConnectionState;
9
9
  (function (ConnectionState) {
10
10
  /**
11
- * The document is no longer connected to the delta server
11
+ * The container is not connected to the ordering service
12
+ * Note - When in this state the container may be about to reconnect,
13
+ * or may remain disconnected until explicitly told to connect.
12
14
  */
13
15
  ConnectionState[ConnectionState["Disconnected"] = 0] = "Disconnected";
14
16
  /**
15
- * The document has an inbound connection but is still pending for outbound deltas
17
+ * The container is disconnected but actively trying to establish a new connection
18
+ * PLEASE NOTE that this numerical value falls out of the order you may expect for this state
19
+ */
20
+ ConnectionState[ConnectionState["EstablishingConnection"] = 3] = "EstablishingConnection";
21
+ /**
22
+ * @see ConnectionState.CatchingUp, which is the new name for this state.
23
+ * @deprecated - This state itself is not gone, just being renamed. Please use ConnectionState.CatchingUp.
16
24
  */
17
25
  ConnectionState[ConnectionState["Connecting"] = 1] = "Connecting";
18
26
  /**
19
- * The document is fully connected
27
+ * The container has an inbound connection only, and is catching up to the latest known state from the service.
28
+ */
29
+ ConnectionState[ConnectionState["CatchingUp"] = 1] = "CatchingUp";
30
+ /**
31
+ * The container is fully connected and syncing
20
32
  */
21
33
  ConnectionState[ConnectionState["Connected"] = 2] = "Connected";
22
34
  })(ConnectionState = exports.ConnectionState || (exports.ConnectionState = {}));
@@ -1 +1 @@
1
- {"version":3,"file":"connectionState.js","sourceRoot":"","sources":["../src/connectionState.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,IAAY,eAeX;AAfD,WAAY,eAAe;IACvB;;OAEG;IACH,qEAAY,CAAA;IAEZ;;OAEG;IACH,iEAAU,CAAA;IAEV;;OAEG;IACH,+DAAS,CAAA;AACb,CAAC,EAfW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAe1B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport enum ConnectionState {\n /**\n * The document is no longer connected to the delta server\n */\n Disconnected,\n\n /**\n * The document has an inbound connection but is still pending for outbound deltas\n */\n Connecting,\n\n /**\n * The document is fully connected\n */\n Connected,\n}\n"]}
1
+ {"version":3,"file":"connectionState.js","sourceRoot":"","sources":["../src/connectionState.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,IAAY,eA6BX;AA7BD,WAAY,eAAe;IACvB;;;;OAIG;IACH,qEAAgB,CAAA;IAEhB;;;OAGG;IACH,yFAA0B,CAAA;IAE1B;;;OAGG;IACH,iEAAc,CAAA;IAEd;;OAEG;IACH,iEAAc,CAAA;IAEd;;OAEG;IACH,+DAAa,CAAA;AACjB,CAAC,EA7BW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QA6B1B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport enum ConnectionState {\n /**\n * The container is not connected to the ordering service\n * Note - When in this state the container may be about to reconnect,\n * or may remain disconnected until explicitly told to connect.\n */\n Disconnected = 0,\n\n /**\n * The container is disconnected but actively trying to establish a new connection\n * PLEASE NOTE that this numerical value falls out of the order you may expect for this state\n */\n EstablishingConnection = 3,\n\n /**\n * @see ConnectionState.CatchingUp, which is the new name for this state.\n * @deprecated - This state itself is not gone, just being renamed. Please use ConnectionState.CatchingUp.\n */\n Connecting = 1,\n\n /**\n * The container has an inbound connection only, and is catching up to the latest known state from the service.\n */\n CatchingUp = 1,\n\n /**\n * The container is fully connected and syncing\n */\n Connected = 2,\n}\n"]}
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
6
6
  import { IConnectionDetails } from "@fluidframework/container-definitions";
7
+ import { ProtocolOpHandler } from "@fluidframework/protocol-base";
7
8
  import { ConnectionMode, IQuorumClients, ISequencedClient } from "@fluidframework/protocol-definitions";
8
9
  import { ConnectionState } from "./connectionState";
9
10
  export interface IConnectionStateHandler {
@@ -20,9 +21,9 @@ export interface ILocalSequencedClient extends ISequencedClient {
20
21
  export declare class ConnectionStateHandler {
21
22
  private readonly handler;
22
23
  private readonly logger;
24
+ private _clientId?;
23
25
  private _connectionState;
24
26
  private _pendingClientId;
25
- private _clientId;
26
27
  private readonly prevClientLeftTimer;
27
28
  private readonly joinOpTimer;
28
29
  private waitEvent;
@@ -30,16 +31,17 @@ export declare class ConnectionStateHandler {
30
31
  get connected(): boolean;
31
32
  get clientId(): string | undefined;
32
33
  get pendingClientId(): string | undefined;
33
- constructor(handler: IConnectionStateHandler, logger: ITelemetryLogger);
34
+ constructor(handler: IConnectionStateHandler, logger: ITelemetryLogger, _clientId?: string | undefined);
34
35
  private startJoinOpTimer;
35
36
  private stopJoinOpTimer;
36
37
  dispose(): void;
37
38
  containerSaved(): void;
38
- receivedAddMemberEvent(clientId: string): void;
39
+ private receivedAddMemberEvent;
39
40
  private applyForConnectedState;
40
- receivedRemoveMemberEvent(clientId: string): void;
41
+ private receivedRemoveMemberEvent;
41
42
  receivedDisconnectEvent(reason: string): void;
42
43
  receivedConnectEvent(connectionMode: ConnectionMode, details: IConnectionDetails): void;
43
44
  private setConnectionState;
45
+ initProtocol(protocol: ProtocolOpHandler): void;
44
46
  }
45
47
  //# sourceMappingURL=connectionStateHandler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connectionStateHandler.d.ts","sourceRoot":"","sources":["../src/connectionStateHandler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAGxG,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,uBAAuB;IACpC,aAAa,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;IAChD,iCAAiC,EAAE,CAC/B,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,eAAe,EACzB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,KAC1B,IAAI,CAAC;IACV,qBAAqB,EAAE,MAAM,OAAO,CAAC;IACrC,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,sBAAsB,EAAE,MAAM,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC3D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAID,qBAAa,sBAAsB;IA0B3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IA1B3B,OAAO,CAAC,gBAAgB,CAAgC;IACxD,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAEpC,OAAO,CAAC,SAAS,CAA+B;IAEhD,IAAW,eAAe,IAAI,eAAe,CAE5C;IAED,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,IAAW,QAAQ,IAAI,MAAM,GAAG,SAAS,CAExC;IAED,IAAW,eAAe,IAAI,MAAM,GAAG,SAAS,CAE/C;gBAGoB,OAAO,EAAE,uBAAuB,EAChC,MAAM,EAAE,gBAAgB;IA4B7C,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,eAAe;IAKhB,OAAO;IAKP,cAAc;IASd,sBAAsB,CAAC,QAAQ,EAAE,MAAM;IAsB9C,OAAO,CAAC,sBAAsB;IA4BvB,yBAAyB,CAAC,QAAQ,EAAE,MAAM;IAQ1C,uBAAuB,CAAC,MAAM,EAAE,MAAM;IAOtC,oBAAoB,CACvB,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,kBAAkB;IAgC/B,OAAO,CAAC,kBAAkB;CAuD7B"}
1
+ {"version":3,"file":"connectionStateHandler.d.ts","sourceRoot":"","sources":["../src/connectionStateHandler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExG,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,uBAAuB;IACpC,aAAa,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;IAChD,iCAAiC,EAAE,CAC/B,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,eAAe,EACzB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,KAC1B,IAAI,CAAC;IACV,qBAAqB,EAAE,MAAM,OAAO,CAAC;IACrC,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,sBAAsB,EAAE,MAAM,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC3D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAID,qBAAa,sBAAsB;IAyB3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,SAAS,CAAC;IA1BtB,OAAO,CAAC,gBAAgB,CAAgC;IACxD,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAEpC,OAAO,CAAC,SAAS,CAA+B;IAEhD,IAAW,eAAe,IAAI,eAAe,CAE5C;IAED,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,IAAW,QAAQ,IAAI,MAAM,GAAG,SAAS,CAExC;IAED,IAAW,eAAe,IAAI,MAAM,GAAG,SAAS,CAE/C;gBAGoB,OAAO,EAAE,uBAAuB,EAChC,MAAM,EAAE,gBAAgB,EACjC,SAAS,CAAC,oBAAQ;IA4B9B,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,eAAe;IAKhB,OAAO;IAKP,cAAc;IASrB,OAAO,CAAC,sBAAsB;IAsB9B,OAAO,CAAC,sBAAsB;IAiC9B,OAAO,CAAC,yBAAyB;IAQ1B,uBAAuB,CAAC,MAAM,EAAE,MAAM;IAOtC,oBAAoB,CACvB,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,kBAAkB;IAgC/B,OAAO,CAAC,kBAAkB;IAwDnB,YAAY,CAAC,QAAQ,EAAE,iBAAiB;CAclD"}
@@ -5,15 +5,16 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.ConnectionStateHandler = void 0;
8
- const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
9
8
  const common_utils_1 = require("@fluidframework/common-utils");
9
+ const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
10
10
  const connectionState_1 = require("./connectionState");
11
11
  const JoinOpTimer = 45000;
12
12
  class ConnectionStateHandler {
13
- constructor(handler, logger) {
13
+ constructor(handler, logger, _clientId) {
14
14
  var _a;
15
15
  this.handler = handler;
16
16
  this.logger = logger;
17
+ this._clientId = _clientId;
17
18
  this._connectionState = connectionState_1.ConnectionState.Disconnected;
18
19
  this.prevClientLeftTimer = new common_utils_1.Timer(
19
20
  // Default is 5 min for which we are going to wait for its own "leave" message. This is same as
@@ -28,7 +29,7 @@ class ConnectionStateHandler {
28
29
  this.joinOpTimer = new common_utils_1.Timer(JoinOpTimer, () => {
29
30
  // I've observed timer firing within couple ms from disconnect event, looks like
30
31
  // queued timer callback is not cancelled if timer is cancelled while callback sits in the queue.
31
- if (this.connectionState === connectionState_1.ConnectionState.Connecting) {
32
+ if (this.connectionState === connectionState_1.ConnectionState.CatchingUp) {
32
33
  this.handler.logConnectionIssue("NoJoinOp");
33
34
  }
34
35
  });
@@ -91,6 +92,8 @@ class ConnectionStateHandler {
91
92
  var _a;
92
93
  const quorumClients = this.handler.quorumClients();
93
94
  (0, common_utils_1.assert)(quorumClients !== undefined, 0x236 /* "In all cases it should be already installed" */);
95
+ (0, common_utils_1.assert)(this.prevClientLeftTimer.hasTimer === false ||
96
+ (this.clientId !== undefined && quorumClients.getMember(this.clientId) !== undefined), 0x2e2 /* "Must only wait for leave message when clientId in quorum" */);
94
97
  // Move to connected state only if we are in Connecting state, we have seen our join op
95
98
  // and there is no timer running which means we are not waiting for previous client to leave
96
99
  // or timeout has occured while doing so.
@@ -130,7 +133,7 @@ class ConnectionStateHandler {
130
133
  }
131
134
  receivedConnectEvent(connectionMode, details) {
132
135
  const oldState = this._connectionState;
133
- this._connectionState = connectionState_1.ConnectionState.Connecting;
136
+ this._connectionState = connectionState_1.ConnectionState.CatchingUp;
134
137
  // Stash the clientID to detect when transitioning from connecting (socket.io channel open) to connected
135
138
  // (have received the join message for the client ID)
136
139
  // This is especially important in the reconnect case. It's possible there could be outstanding
@@ -139,7 +142,7 @@ class ConnectionStateHandler {
139
142
  // we know there can no longer be outstanding ops that we sent with the previous client id.
140
143
  this._pendingClientId = details.clientId;
141
144
  // Report telemetry after we set client id, but before transitioning to Connected state below!
142
- this.handler.logConnectionStateChangeTelemetry(connectionState_1.ConnectionState.Connecting, oldState);
145
+ this.handler.logConnectionStateChangeTelemetry(connectionState_1.ConnectionState.CatchingUp, oldState);
143
146
  const quorumClients = this.handler.quorumClients();
144
147
  // Check if we already processed our own join op through delta storage!
145
148
  // we are fetching ops from storage in parallel to connecting to ordering service
@@ -169,7 +172,7 @@ class ConnectionStateHandler {
169
172
  client = quorumClients === null || quorumClients === void 0 ? void 0 : quorumClients.getMember(this._clientId);
170
173
  }
171
174
  if (value === connectionState_1.ConnectionState.Connected) {
172
- (0, common_utils_1.assert)(oldState === connectionState_1.ConnectionState.Connecting, 0x1d8 /* "Should only transition from Connecting state" */);
175
+ (0, common_utils_1.assert)(oldState === connectionState_1.ConnectionState.CatchingUp, 0x1d8 /* "Should only transition from Connecting state" */);
173
176
  // Mark our old client should have left in the quorum if it's still there
174
177
  if (client !== undefined) {
175
178
  client.shouldHaveLeft = true;
@@ -205,6 +208,18 @@ class ConnectionStateHandler {
205
208
  // Propagate event across layers
206
209
  this.handler.connectionStateChanged();
207
210
  }
211
+ initProtocol(protocol) {
212
+ protocol.quorum.on("addMember", (clientId, details) => {
213
+ this.receivedAddMemberEvent(clientId);
214
+ });
215
+ protocol.quorum.on("removeMember", (clientId) => {
216
+ this.receivedRemoveMemberEvent(clientId);
217
+ });
218
+ // if we have a clientId from a previous container we need to wait for its leave message
219
+ if (this.clientId !== undefined && protocol.quorum.getMember(this.clientId) !== undefined) {
220
+ this.prevClientLeftTimer.restart();
221
+ }
222
+ }
208
223
  }
209
224
  exports.ConnectionStateHandler = ConnectionStateHandler;
210
225
  //# sourceMappingURL=connectionStateHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"connectionStateHandler.js","sourceRoot":"","sources":["../src/connectionStateHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { IConnectionDetails } from \"@fluidframework/container-definitions\";\nimport { ConnectionMode, IQuorumClients, ISequencedClient } from \"@fluidframework/protocol-definitions\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { assert, Timer } from \"@fluidframework/common-utils\";\nimport { ConnectionState } from \"./connectionState\";\n\nexport interface IConnectionStateHandler {\n quorumClients: () => IQuorumClients | undefined;\n logConnectionStateChangeTelemetry: (\n value: ConnectionState,\n oldState: ConnectionState,\n reason?: string | undefined\n ) => void;\n shouldClientJoinWrite: () => boolean;\n maxClientLeaveWaitTime: number | undefined;\n logConnectionIssue: (eventName: string) => void;\n connectionStateChanged: () => void;\n}\n\nexport interface ILocalSequencedClient extends ISequencedClient {\n shouldHaveLeft?: boolean;\n}\n\nconst JoinOpTimer = 45000;\n\nexport class ConnectionStateHandler {\n private _connectionState = ConnectionState.Disconnected;\n private _pendingClientId: string | undefined;\n private _clientId: string | undefined;\n private readonly prevClientLeftTimer: Timer;\n private readonly joinOpTimer: Timer;\n\n private waitEvent: PerformanceEvent | undefined;\n\n public get connectionState(): ConnectionState {\n return this._connectionState;\n }\n\n public get connected(): boolean {\n return this.connectionState === ConnectionState.Connected;\n }\n\n public get clientId(): string | undefined {\n return this._clientId;\n }\n\n public get pendingClientId(): string | undefined {\n return this._pendingClientId;\n }\n\n constructor(\n private readonly handler: IConnectionStateHandler,\n private readonly logger: ITelemetryLogger,\n ) {\n this.prevClientLeftTimer = new Timer(\n // Default is 5 min for which we are going to wait for its own \"leave\" message. This is same as\n // the max time on server after which leave op is sent.\n this.handler.maxClientLeaveWaitTime ?? 300000,\n () => {\n assert(!this.connected,\n 0x2ac /* \"Connected when timeout waiting for leave from previous session fired!\" */);\n this.applyForConnectedState(\"timeout\");\n },\n );\n\n // Based on recent data, it looks like majority of cases where we get stuck are due to really slow or\n // timing out ops fetches. So attempt recovery infrequently. Also fetch uses 30 second timeout, so\n // if retrying fixes the problem, we should not see these events.\n this.joinOpTimer = new Timer(\n JoinOpTimer,\n () => {\n // I've observed timer firing within couple ms from disconnect event, looks like\n // queued timer callback is not cancelled if timer is cancelled while callback sits in the queue.\n if (this.connectionState === ConnectionState.Connecting) {\n this.handler.logConnectionIssue(\"NoJoinOp\");\n }\n },\n );\n }\n\n private startJoinOpTimer() {\n assert(!this.joinOpTimer.hasTimer, 0x234 /* \"has joinOpTimer\" */);\n this.joinOpTimer.start();\n }\n\n private stopJoinOpTimer() {\n assert(this.joinOpTimer.hasTimer, 0x235 /* \"no joinOpTimer\" */);\n this.joinOpTimer.clear();\n }\n\n public dispose() {\n assert(!this.joinOpTimer.hasTimer, 0x2a5 /* \"join timer\" */);\n this.prevClientLeftTimer.clear();\n }\n\n public containerSaved() {\n // If we were waiting for moving to Connected state, then only apply for state change. Since the container\n // is now saved and we don't have any ops to roundtrip, we can clear the timer and apply for connected state.\n if (this.prevClientLeftTimer.hasTimer) {\n this.prevClientLeftTimer.clear();\n this.applyForConnectedState(\"containerSaved\");\n }\n }\n\n public receivedAddMemberEvent(clientId: string) {\n // This is the only one that requires the pending client ID\n if (clientId === this.pendingClientId) {\n if (this.joinOpTimer.hasTimer) {\n this.stopJoinOpTimer();\n } else {\n // timer has already fired, meaning it took too long to get join on.\n // Record how long it actually took to recover.\n this.handler.logConnectionIssue(\"ReceivedJoinOp\");\n }\n // Start the event in case we are waiting for leave or timeout.\n if (this.prevClientLeftTimer.hasTimer) {\n this.waitEvent = PerformanceEvent.start(this.logger, {\n eventName: \"WaitBeforeClientLeave\",\n waitOnClientId: this._clientId,\n hadOutstandingOps: this.handler.shouldClientJoinWrite(),\n });\n }\n this.applyForConnectedState(\"addMemberEvent\");\n }\n }\n\n private applyForConnectedState(source: \"removeMemberEvent\" | \"addMemberEvent\" | \"timeout\" | \"containerSaved\") {\n const quorumClients = this.handler.quorumClients();\n assert(quorumClients !== undefined, 0x236 /* \"In all cases it should be already installed\" */);\n // Move to connected state only if we are in Connecting state, we have seen our join op\n // and there is no timer running which means we are not waiting for previous client to leave\n // or timeout has occured while doing so.\n if (this.pendingClientId !== this.clientId\n && this.pendingClientId !== undefined\n && quorumClients.getMember(this.pendingClientId) !== undefined\n && !this.prevClientLeftTimer.hasTimer\n ) {\n this.waitEvent?.end({ source });\n this.setConnectionState(ConnectionState.Connected);\n } else {\n // Adding this event temporarily so that we can get help debugging if something goes wrong.\n this.logger.sendTelemetryEvent({\n eventName: \"connectedStateRejected\",\n category: source === \"timeout\" ? \"error\" : \"generic\",\n source,\n pendingClientId: this.pendingClientId,\n clientId: this.clientId,\n hasTimer: this.prevClientLeftTimer.hasTimer,\n inQuorum: quorumClients !== undefined && this.pendingClientId !== undefined\n && quorumClients.getMember(this.pendingClientId) !== undefined,\n });\n }\n }\n\n public receivedRemoveMemberEvent(clientId: string) {\n // If the client which has left was us, then finish the timer.\n if (this.clientId === clientId) {\n this.prevClientLeftTimer.clear();\n this.applyForConnectedState(\"removeMemberEvent\");\n }\n }\n\n public receivedDisconnectEvent(reason: string) {\n if (this.joinOpTimer.hasTimer) {\n this.stopJoinOpTimer();\n }\n this.setConnectionState(ConnectionState.Disconnected, reason);\n }\n\n public receivedConnectEvent(\n connectionMode: ConnectionMode,\n details: IConnectionDetails,\n ) {\n const oldState = this._connectionState;\n this._connectionState = ConnectionState.Connecting;\n\n // Stash the clientID to detect when transitioning from connecting (socket.io channel open) to connected\n // (have received the join message for the client ID)\n // This is especially important in the reconnect case. It's possible there could be outstanding\n // ops sent by this client, so we should keep the old client id until we see our own client's\n // join message. after we see the join message for out new connection with our new client id,\n // we know there can no longer be outstanding ops that we sent with the previous client id.\n this._pendingClientId = details.clientId;\n\n // Report telemetry after we set client id, but before transitioning to Connected state below!\n this.handler.logConnectionStateChangeTelemetry(ConnectionState.Connecting, oldState);\n\n const quorumClients = this.handler.quorumClients();\n // Check if we already processed our own join op through delta storage!\n // we are fetching ops from storage in parallel to connecting to ordering service\n // Given async processes, it's possible that we have already processed our own join message before\n // connection was fully established.\n // Note that we might be still initializing quorum - connection is established proactively on load!\n if (quorumClients?.getMember(details.clientId) !== undefined\n || connectionMode === \"read\"\n ) {\n assert(!this.prevClientLeftTimer.hasTimer, 0x2a6 /* \"there should be no timer for 'read' connections\" */);\n this.setConnectionState(ConnectionState.Connected);\n } else if (connectionMode === \"write\") {\n this.startJoinOpTimer();\n }\n }\n\n private setConnectionState(value: ConnectionState.Disconnected, reason: string);\n private setConnectionState(value: ConnectionState.Connected);\n private setConnectionState(value: ConnectionState, reason?: string) {\n if (this.connectionState === value) {\n // Already in the desired state - exit early\n this.logger.sendErrorEvent({ eventName: \"setConnectionStateSame\", value });\n return;\n }\n\n const oldState = this._connectionState;\n this._connectionState = value;\n const quorumClients = this.handler.quorumClients();\n let client: ILocalSequencedClient | undefined;\n if (this._clientId !== undefined) {\n client = quorumClients?.getMember(this._clientId);\n }\n if (value === ConnectionState.Connected) {\n assert(oldState === ConnectionState.Connecting,\n 0x1d8 /* \"Should only transition from Connecting state\" */);\n // Mark our old client should have left in the quorum if it's still there\n if (client !== undefined) {\n client.shouldHaveLeft = true;\n }\n this._clientId = this.pendingClientId;\n } else if (value === ConnectionState.Disconnected) {\n // Important as we process our own joinSession message through delta request\n this._pendingClientId = undefined;\n // Only wait for \"leave\" message if the connected client exists in the quorum because only the write\n // client will exist in the quorum and only for those clients we will receive \"removeMember\" event and\n // the client has some unacked ops.\n // Also server would not accept ops from read client. Also check if the timer is not already running as\n // we could receive \"Disconnected\" event multiple times without getting connected and in that case we\n // don't want to reset the timer as we still want to wait on original client which started this timer.\n if (client !== undefined\n && this.handler.shouldClientJoinWrite()\n && this.prevClientLeftTimer.hasTimer === false\n ) {\n this.prevClientLeftTimer.restart();\n } else {\n // Adding this event temporarily so that we can get help debugging if something goes wrong.\n this.logger.sendTelemetryEvent({\n eventName: \"noWaitOnDisconnected\",\n inQuorum: client !== undefined,\n hasTimer: this.prevClientLeftTimer.hasTimer,\n shouldClientJoinWrite: this.handler.shouldClientJoinWrite(),\n });\n }\n }\n\n // Report transition before we propagate event across layers\n this.handler.logConnectionStateChangeTelemetry(this._connectionState, oldState, reason);\n\n // Propagate event across layers\n this.handler.connectionStateChanged();\n }\n}\n"]}
1
+ {"version":3,"file":"connectionStateHandler.js","sourceRoot":"","sources":["../src/connectionStateHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { assert, Timer } from \"@fluidframework/common-utils\";\nimport { IConnectionDetails } from \"@fluidframework/container-definitions\";\nimport { ProtocolOpHandler } from \"@fluidframework/protocol-base\";\nimport { ConnectionMode, IQuorumClients, ISequencedClient } from \"@fluidframework/protocol-definitions\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { ConnectionState } from \"./connectionState\";\n\nexport interface IConnectionStateHandler {\n quorumClients: () => IQuorumClients | undefined;\n logConnectionStateChangeTelemetry: (\n value: ConnectionState,\n oldState: ConnectionState,\n reason?: string | undefined\n ) => void;\n shouldClientJoinWrite: () => boolean;\n maxClientLeaveWaitTime: number | undefined;\n logConnectionIssue: (eventName: string) => void;\n connectionStateChanged: () => void;\n}\n\nexport interface ILocalSequencedClient extends ISequencedClient {\n shouldHaveLeft?: boolean;\n}\n\nconst JoinOpTimer = 45000;\n\nexport class ConnectionStateHandler {\n private _connectionState = ConnectionState.Disconnected;\n private _pendingClientId: string | undefined;\n private readonly prevClientLeftTimer: Timer;\n private readonly joinOpTimer: Timer;\n\n private waitEvent: PerformanceEvent | undefined;\n\n public get connectionState(): ConnectionState {\n return this._connectionState;\n }\n\n public get connected(): boolean {\n return this.connectionState === ConnectionState.Connected;\n }\n\n public get clientId(): string | undefined {\n return this._clientId;\n }\n\n public get pendingClientId(): string | undefined {\n return this._pendingClientId;\n }\n\n constructor(\n private readonly handler: IConnectionStateHandler,\n private readonly logger: ITelemetryLogger,\n private _clientId?: string,\n ) {\n this.prevClientLeftTimer = new Timer(\n // Default is 5 min for which we are going to wait for its own \"leave\" message. This is same as\n // the max time on server after which leave op is sent.\n this.handler.maxClientLeaveWaitTime ?? 300000,\n () => {\n assert(!this.connected,\n 0x2ac /* \"Connected when timeout waiting for leave from previous session fired!\" */);\n this.applyForConnectedState(\"timeout\");\n },\n );\n\n // Based on recent data, it looks like majority of cases where we get stuck are due to really slow or\n // timing out ops fetches. So attempt recovery infrequently. Also fetch uses 30 second timeout, so\n // if retrying fixes the problem, we should not see these events.\n this.joinOpTimer = new Timer(\n JoinOpTimer,\n () => {\n // I've observed timer firing within couple ms from disconnect event, looks like\n // queued timer callback is not cancelled if timer is cancelled while callback sits in the queue.\n if (this.connectionState === ConnectionState.CatchingUp) {\n this.handler.logConnectionIssue(\"NoJoinOp\");\n }\n },\n );\n }\n\n private startJoinOpTimer() {\n assert(!this.joinOpTimer.hasTimer, 0x234 /* \"has joinOpTimer\" */);\n this.joinOpTimer.start();\n }\n\n private stopJoinOpTimer() {\n assert(this.joinOpTimer.hasTimer, 0x235 /* \"no joinOpTimer\" */);\n this.joinOpTimer.clear();\n }\n\n public dispose() {\n assert(!this.joinOpTimer.hasTimer, 0x2a5 /* \"join timer\" */);\n this.prevClientLeftTimer.clear();\n }\n\n public containerSaved() {\n // If we were waiting for moving to Connected state, then only apply for state change. Since the container\n // is now saved and we don't have any ops to roundtrip, we can clear the timer and apply for connected state.\n if (this.prevClientLeftTimer.hasTimer) {\n this.prevClientLeftTimer.clear();\n this.applyForConnectedState(\"containerSaved\");\n }\n }\n\n private receivedAddMemberEvent(clientId: string) {\n // This is the only one that requires the pending client ID\n if (clientId === this.pendingClientId) {\n if (this.joinOpTimer.hasTimer) {\n this.stopJoinOpTimer();\n } else {\n // timer has already fired, meaning it took too long to get join on.\n // Record how long it actually took to recover.\n this.handler.logConnectionIssue(\"ReceivedJoinOp\");\n }\n // Start the event in case we are waiting for leave or timeout.\n if (this.prevClientLeftTimer.hasTimer) {\n this.waitEvent = PerformanceEvent.start(this.logger, {\n eventName: \"WaitBeforeClientLeave\",\n waitOnClientId: this._clientId,\n hadOutstandingOps: this.handler.shouldClientJoinWrite(),\n });\n }\n this.applyForConnectedState(\"addMemberEvent\");\n }\n }\n\n private applyForConnectedState(source: \"removeMemberEvent\" | \"addMemberEvent\" | \"timeout\" | \"containerSaved\") {\n const quorumClients = this.handler.quorumClients();\n assert(quorumClients !== undefined, 0x236 /* \"In all cases it should be already installed\" */);\n\n assert(this.prevClientLeftTimer.hasTimer === false ||\n (this.clientId !== undefined && quorumClients.getMember(this.clientId) !== undefined),\n 0x2e2 /* \"Must only wait for leave message when clientId in quorum\" */);\n\n // Move to connected state only if we are in Connecting state, we have seen our join op\n // and there is no timer running which means we are not waiting for previous client to leave\n // or timeout has occured while doing so.\n if (this.pendingClientId !== this.clientId\n && this.pendingClientId !== undefined\n && quorumClients.getMember(this.pendingClientId) !== undefined\n && !this.prevClientLeftTimer.hasTimer\n ) {\n this.waitEvent?.end({ source });\n this.setConnectionState(ConnectionState.Connected);\n } else {\n // Adding this event temporarily so that we can get help debugging if something goes wrong.\n this.logger.sendTelemetryEvent({\n eventName: \"connectedStateRejected\",\n category: source === \"timeout\" ? \"error\" : \"generic\",\n source,\n pendingClientId: this.pendingClientId,\n clientId: this.clientId,\n hasTimer: this.prevClientLeftTimer.hasTimer,\n inQuorum: quorumClients !== undefined && this.pendingClientId !== undefined\n && quorumClients.getMember(this.pendingClientId) !== undefined,\n });\n }\n }\n\n private receivedRemoveMemberEvent(clientId: string) {\n // If the client which has left was us, then finish the timer.\n if (this.clientId === clientId) {\n this.prevClientLeftTimer.clear();\n this.applyForConnectedState(\"removeMemberEvent\");\n }\n }\n\n public receivedDisconnectEvent(reason: string) {\n if (this.joinOpTimer.hasTimer) {\n this.stopJoinOpTimer();\n }\n this.setConnectionState(ConnectionState.Disconnected, reason);\n }\n\n public receivedConnectEvent(\n connectionMode: ConnectionMode,\n details: IConnectionDetails,\n ) {\n const oldState = this._connectionState;\n this._connectionState = ConnectionState.CatchingUp;\n\n // Stash the clientID to detect when transitioning from connecting (socket.io channel open) to connected\n // (have received the join message for the client ID)\n // This is especially important in the reconnect case. It's possible there could be outstanding\n // ops sent by this client, so we should keep the old client id until we see our own client's\n // join message. after we see the join message for out new connection with our new client id,\n // we know there can no longer be outstanding ops that we sent with the previous client id.\n this._pendingClientId = details.clientId;\n\n // Report telemetry after we set client id, but before transitioning to Connected state below!\n this.handler.logConnectionStateChangeTelemetry(ConnectionState.CatchingUp, oldState);\n\n const quorumClients = this.handler.quorumClients();\n // Check if we already processed our own join op through delta storage!\n // we are fetching ops from storage in parallel to connecting to ordering service\n // Given async processes, it's possible that we have already processed our own join message before\n // connection was fully established.\n // Note that we might be still initializing quorum - connection is established proactively on load!\n if (quorumClients?.getMember(details.clientId) !== undefined\n || connectionMode === \"read\"\n ) {\n assert(!this.prevClientLeftTimer.hasTimer, 0x2a6 /* \"there should be no timer for 'read' connections\" */);\n this.setConnectionState(ConnectionState.Connected);\n } else if (connectionMode === \"write\") {\n this.startJoinOpTimer();\n }\n }\n\n private setConnectionState(value: ConnectionState.Disconnected, reason: string);\n private setConnectionState(value: ConnectionState.Connected);\n private setConnectionState(value: ConnectionState, reason?: string) {\n if (this.connectionState === value) {\n // Already in the desired state - exit early\n this.logger.sendErrorEvent({ eventName: \"setConnectionStateSame\", value });\n return;\n }\n\n const oldState = this._connectionState;\n this._connectionState = value;\n const quorumClients = this.handler.quorumClients();\n let client: ILocalSequencedClient | undefined;\n if (this._clientId !== undefined) {\n client = quorumClients?.getMember(this._clientId);\n }\n if (value === ConnectionState.Connected) {\n assert(oldState === ConnectionState.CatchingUp,\n 0x1d8 /* \"Should only transition from Connecting state\" */);\n // Mark our old client should have left in the quorum if it's still there\n if (client !== undefined) {\n client.shouldHaveLeft = true;\n }\n this._clientId = this.pendingClientId;\n } else if (value === ConnectionState.Disconnected) {\n // Important as we process our own joinSession message through delta request\n this._pendingClientId = undefined;\n // Only wait for \"leave\" message if the connected client exists in the quorum because only the write\n // client will exist in the quorum and only for those clients we will receive \"removeMember\" event and\n // the client has some unacked ops.\n // Also server would not accept ops from read client. Also check if the timer is not already running as\n // we could receive \"Disconnected\" event multiple times without getting connected and in that case we\n // don't want to reset the timer as we still want to wait on original client which started this timer.\n if (client !== undefined\n && this.handler.shouldClientJoinWrite()\n && this.prevClientLeftTimer.hasTimer === false\n ) {\n this.prevClientLeftTimer.restart();\n } else {\n // Adding this event temporarily so that we can get help debugging if something goes wrong.\n this.logger.sendTelemetryEvent({\n eventName: \"noWaitOnDisconnected\",\n inQuorum: client !== undefined,\n hasTimer: this.prevClientLeftTimer.hasTimer,\n shouldClientJoinWrite: this.handler.shouldClientJoinWrite(),\n });\n }\n }\n\n // Report transition before we propagate event across layers\n this.handler.logConnectionStateChangeTelemetry(this._connectionState, oldState, reason);\n\n // Propagate event across layers\n this.handler.connectionStateChanged();\n }\n\n public initProtocol(protocol: ProtocolOpHandler) {\n protocol.quorum.on(\"addMember\", (clientId, details) => {\n this.receivedAddMemberEvent(clientId);\n });\n\n protocol.quorum.on(\"removeMember\", (clientId) => {\n this.receivedRemoveMemberEvent(clientId);\n });\n\n // if we have a clientId from a previous container we need to wait for its leave message\n if (this.clientId !== undefined && protocol.quorum.getMember(this.clientId) !== undefined) {\n this.prevClientLeftTimer.restart();\n }\n }\n}\n"]}
@@ -5,7 +5,7 @@
5
5
  import { IRequest, IResponse, IFluidRouter } from "@fluidframework/core-interfaces";
6
6
  import { IAudience, IContainer, IContainerEvents, IDeltaManager, ICriticalContainerError, AttachState, ReadOnlyInfo, IContainerLoadMode, IFluidCodeDetails } from "@fluidframework/container-definitions";
7
7
  import { IDocumentStorageService, IFluidResolvedUrl, IResolvedUrl } from "@fluidframework/driver-definitions";
8
- import { IClientConfiguration, IClientDetails, IDocumentMessage, IQuorumClients, ISequencedDocumentMessage, IVersion } from "@fluidframework/protocol-definitions";
8
+ import { IClientConfiguration, IClientDetails, IDocumentMessage, IProtocolState, IQuorumClients, ISequencedDocumentMessage, IVersion } from "@fluidframework/protocol-definitions";
9
9
  import { EventEmitterWithErrorHandling, TelemetryLogger } from "@fluidframework/telemetry-utils";
10
10
  import { ILoaderOptions, Loader } from "./loader";
11
11
  import { ConnectionState } from "./connectionState";
@@ -35,26 +35,41 @@ export interface IContainerConfig {
35
35
  * Client details provided in the override will be merged over the default client.
36
36
  */
37
37
  clientDetailsOverride?: IClientDetails;
38
+ /**
39
+ * Serialized state from a previous instance of this container
40
+ */
41
+ serializedContainerState?: IPendingContainerState;
38
42
  }
39
43
  /**
40
44
  * Waits until container connects to delta storage and gets up-to-date
41
45
  * Useful when resolving URIs and hitting 404, due to container being loaded from (stale) snapshot and not being
42
46
  * up to date. Host may chose to wait in such case and retry resolving URI.
43
47
  * Warning: Will wait infinitely for connection to establish if there is no connection.
44
- * May result in deadlock if Container.setAutoReconnect(false) is called and never switched back to auto-reconnect.
48
+ * May result in deadlock if Container.disconnect() is called and never followed by a call to Container.connect().
45
49
  * @returns true: container is up to date, it processed all the ops that were know at the time of first connection
46
50
  * false: storage does not provide indication of how far the client is. Container processed
47
51
  * all the ops known to it, but it maybe still behind.
48
52
  * @throws an error beginning with `"Container closed"` if the container is closed before it catches up.
49
53
  */
50
54
  export declare function waitContainerToCatchUp(container: IContainer): Promise<boolean>;
55
+ /**
56
+ * State saved by a container at close time, to be used to load a new instance
57
+ * of the container to the same state
58
+ */
59
+ export interface IPendingContainerState {
60
+ pendingRuntimeState: unknown;
61
+ url: string;
62
+ protocol: IProtocolState;
63
+ term: number;
64
+ clientId?: string;
65
+ }
51
66
  export declare class Container extends EventEmitterWithErrorHandling<IContainerEvents> implements IContainer {
52
67
  private readonly loader;
53
68
  static version: string;
54
69
  /**
55
70
  * Load an existing container.
56
71
  */
57
- static load(loader: Loader, loadOptions: IContainerLoadOptions, pendingLocalState?: unknown): Promise<Container>;
72
+ static load(loader: Loader, loadOptions: IContainerLoadOptions, pendingLocalState?: IPendingContainerState): Promise<Container>;
58
73
  /**
59
74
  * Create a new container in a detached state.
60
75
  */
@@ -163,27 +178,11 @@ export declare class Container extends EventEmitterWithErrorHandling<IContainerE
163
178
  serialize(): string;
164
179
  attach(request: IRequest): Promise<void>;
165
180
  request(path: IRequest): Promise<IResponse>;
166
- /**
167
- * Dictates whether or not the current container will automatically attempt to reconnect to the delta stream
168
- * after receiving a disconnect event
169
- * @param reconnect - Boolean indicating if reconnect should automatically occur
170
- * @deprecated - 0.58, This API will be removed in 1.0
171
- * Use `connect()` and `disconnect()` instead of `setAutoReconnect(true)` and `setAutoReconnect(false)` respectively
172
- * See https://github.com/microsoft/FluidFramework/issues/9167 for context
173
- */
174
- setAutoReconnect(reconnect: boolean): void;
175
181
  private setAutoReconnectInternal;
176
182
  connect(): void;
177
183
  private connectInternal;
178
184
  disconnect(): void;
179
185
  private disconnectInternal;
180
- /**
181
- * Have the container attempt to resume processing ops
182
- * @deprecated - 0.58, This API will be removed in 1.0
183
- * Use `connect()` instead
184
- * See https://github.com/microsoft/FluidFramework/issues/9167 for context
185
- */
186
- resume(): void;
187
186
  private resumeInternal;
188
187
  getAbsoluteUrl(relativeUrl: string): Promise<string | undefined>;
189
188
  proposeCodeDetails(codeDetails: IFluidCodeDetails): Promise<boolean>;
@@ -222,13 +221,6 @@ export declare class Container extends EventEmitterWithErrorHandling<IContainerE
222
221
  private submitContainerMessage;
223
222
  private submitMessage;
224
223
  private processRemoteMessage;
225
- /**
226
- * #260 (ADO)
227
- * back-compat: noopTimeFrequency & noopCountFrequency properties were added to
228
- * IClientConfiguration in 0.59.3000. During the integration, we must read the
229
- * available configuration from the loader options.
230
- */
231
- private getNoopConfig;
232
224
  private submitSignal;
233
225
  private processSignal;
234
226
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"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"}