@fluidframework/container-runtime 0.56.6 → 0.56.7

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.
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/container-runtime";
8
- export declare const pkgVersion = "0.56.6";
8
+ export declare const pkgVersion = "0.56.7";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/container-runtime";
8
- export const pkgVersion = "0.56.6";
8
+ export const pkgVersion = "0.56.7";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"0.56.6\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,mCAAmC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/container-runtime\";\nexport const pkgVersion = \"0.56.7\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-runtime",
3
- "version": "0.56.6",
3
+ "version": "0.56.7",
4
4
  "description": "Fluid container runtime",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": "https://github.com/microsoft/FluidFramework",
@@ -59,26 +59,26 @@
59
59
  "@fluidframework/common-definitions": "^0.20.1",
60
60
  "@fluidframework/common-utils": "^0.32.1",
61
61
  "@fluidframework/container-definitions": "^0.45.0",
62
- "@fluidframework/container-runtime-definitions": "^0.56.6",
63
- "@fluidframework/container-utils": "^0.56.6",
62
+ "@fluidframework/container-runtime-definitions": "^0.56.7",
63
+ "@fluidframework/container-utils": "^0.56.7",
64
64
  "@fluidframework/core-interfaces": "^0.42.0",
65
- "@fluidframework/datastore": "^0.56.6",
65
+ "@fluidframework/datastore": "^0.56.7",
66
66
  "@fluidframework/driver-definitions": "^0.44.0",
67
- "@fluidframework/driver-utils": "^0.56.6",
68
- "@fluidframework/garbage-collector": "^0.56.6",
67
+ "@fluidframework/driver-utils": "^0.56.7",
68
+ "@fluidframework/garbage-collector": "^0.56.7",
69
69
  "@fluidframework/protocol-base": "^0.1034.0",
70
70
  "@fluidframework/protocol-definitions": "^0.1026.0",
71
- "@fluidframework/runtime-definitions": "^0.56.6",
72
- "@fluidframework/runtime-utils": "^0.56.6",
73
- "@fluidframework/telemetry-utils": "^0.56.6",
71
+ "@fluidframework/runtime-definitions": "^0.56.7",
72
+ "@fluidframework/runtime-utils": "^0.56.7",
73
+ "@fluidframework/telemetry-utils": "^0.56.7",
74
74
  "double-ended-queue": "^2.1.0-0",
75
75
  "uuid": "^8.3.1"
76
76
  },
77
77
  "devDependencies": {
78
78
  "@fluidframework/build-common": "^0.23.0",
79
79
  "@fluidframework/eslint-config-fluid": "^0.25.0",
80
- "@fluidframework/mocha-test-setup": "^0.56.6",
81
- "@fluidframework/test-runtime-utils": "^0.56.6",
80
+ "@fluidframework/mocha-test-setup": "^0.56.7",
81
+ "@fluidframework/test-runtime-utils": "^0.56.7",
82
82
  "@microsoft/api-extractor": "^7.16.1",
83
83
  "@rushstack/eslint-config": "^2.5.1",
84
84
  "@types/double-ended-queue": "^2.1.0",
@@ -2,7 +2,8 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
-
5
+ // See #9219
6
+ /* eslint-disable max-lines */
6
7
  import { EventEmitter } from "events";
7
8
  import { ITelemetryBaseLogger, ITelemetryGenericEvent, ITelemetryLogger } from "@fluidframework/common-definitions";
8
9
  import {
@@ -301,6 +302,7 @@ interface OldContainerContextWithLogger extends IContainerContext {
301
302
 
302
303
  // Local storage key to set the default flush mode to TurnBased
303
304
  const turnBasedFlushModeKey = "Fluid.ContainerRuntime.FlushModeTurnBased";
305
+ const maxConsecutiveReconnectsKey = "Fluid.ContainerRuntime.MaxConsecutiveReconnects";
304
306
 
305
307
  export enum RuntimeMessage {
306
308
  FluidDataStoreOp = "component",
@@ -854,6 +856,9 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
854
856
 
855
857
  private readonly summarizerNode: IRootSummarizerNodeWithGC;
856
858
 
859
+ private readonly maxConsecutiveReconnects: number;
860
+ private readonly defaultMaxConsecutiveReconnects = 15;
861
+
857
862
  private _orderSequentiallyCalls: number = 0;
858
863
  private _flushMode: FlushMode;
859
864
  private needsFlush = false;
@@ -863,6 +868,8 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
863
868
 
864
869
  private paused: boolean = false;
865
870
 
871
+ private consecutiveReconnects = 0;
872
+
866
873
  public get connected(): boolean {
867
874
  return this._connected;
868
875
  }
@@ -990,6 +997,10 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
990
997
  const timestamp = client?.timestamp;
991
998
  return this.deltaManager.lastMessage?.timestamp ?? timestamp ?? Date.now();
992
999
  };
1000
+
1001
+ this.maxConsecutiveReconnects =
1002
+ this.mc.config.getNumber(maxConsecutiveReconnectsKey) ?? this.defaultMaxConsecutiveReconnects;
1003
+
993
1004
  this.garbageCollector = GarbageCollector.create(
994
1005
  this,
995
1006
  this.runtimeOptions.gcOptions,
@@ -1415,6 +1426,42 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1415
1426
  }
1416
1427
  }
1417
1428
 
1429
+ // Track how many times the container tries to reconnect with pending messages.
1430
+ // This happens when the connection state is changed and we reset the counter
1431
+ // when we are able to process a local op or when there are no pending messages.
1432
+ // If this counter reaches a max, it's a good indicator that the container
1433
+ // is not making progress and it is stuck in a retry loop.
1434
+ private shouldContinueReconnecting(): boolean {
1435
+ if (this.maxConsecutiveReconnects <= 0) {
1436
+ // Feature disabled, we never stop reconnecting
1437
+ return true;
1438
+ }
1439
+
1440
+ if (!this.pendingStateManager.hasPendingMessages()) {
1441
+ // If there are no pending messages, we can always reconnect
1442
+ this.resetReconnectCount();
1443
+ return true;
1444
+ }
1445
+
1446
+ this.consecutiveReconnects++;
1447
+ if (this.consecutiveReconnects === Math.floor(this.maxConsecutiveReconnects / 2)) {
1448
+ // If we're halfway through the max reconnects, send an event in order
1449
+ // to better identify false positives, if any. If the rate of this event
1450
+ // matches `MaxReconnectsWithNoProgress`, we can safely cut down
1451
+ // maxConsecutiveReconnects to half.
1452
+ this.mc.logger.sendTelemetryEvent({
1453
+ eventName: "ReconnectsWithNoProgress",
1454
+ attempts: this.consecutiveReconnects,
1455
+ });
1456
+ }
1457
+
1458
+ return this.consecutiveReconnects < this.maxConsecutiveReconnects;
1459
+ }
1460
+
1461
+ private resetReconnectCount() {
1462
+ this.consecutiveReconnects = 0;
1463
+ }
1464
+
1418
1465
  private replayPendingStates() {
1419
1466
  // We need to be able to send ops to replay states
1420
1467
  if (!this.canSendOps()) { return; }
@@ -1495,6 +1542,14 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1495
1542
  if (changeOfState) {
1496
1543
  this.deltaManager.off("op", this.onOp);
1497
1544
  this.context.pendingLocalState = undefined;
1545
+ if (!this.shouldContinueReconnecting()) {
1546
+ this.closeFn(new GenericError(
1547
+ "MaxReconnectsWithNoProgress",
1548
+ undefined, // error
1549
+ { attempts: this.consecutiveReconnects }));
1550
+ return;
1551
+ }
1552
+
1498
1553
  this.replayPendingStates();
1499
1554
  }
1500
1555
 
@@ -1558,6 +1613,13 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
1558
1613
 
1559
1614
  this.emit("op", message);
1560
1615
  this.scheduleManager.afterOpProcessing(undefined, message);
1616
+
1617
+ if (local) {
1618
+ // If we have processed a local op, this means that the container is
1619
+ // making progress and we can reset the counter for how many times
1620
+ // we have consecutively replayed the pending states
1621
+ this.resetReconnectCount();
1622
+ }
1561
1623
  } catch (e) {
1562
1624
  this.scheduleManager.afterOpProcessing(e, message);
1563
1625
  throw e;
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-runtime";
9
- export const pkgVersion = "0.56.6";
9
+ export const pkgVersion = "0.56.7";