@fluidframework/container-loader 0.57.0-51086 → 0.58.0-55561

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 (54) hide show
  1. package/dist/connectionManager.d.ts +2 -2
  2. package/dist/connectionManager.d.ts.map +1 -1
  3. package/dist/connectionManager.js +8 -12
  4. package/dist/connectionManager.js.map +1 -1
  5. package/dist/connectionStateHandler.d.ts +2 -3
  6. package/dist/connectionStateHandler.d.ts.map +1 -1
  7. package/dist/connectionStateHandler.js +9 -10
  8. package/dist/connectionStateHandler.js.map +1 -1
  9. package/dist/container.d.ts.map +1 -1
  10. package/dist/container.js +10 -9
  11. package/dist/container.js.map +1 -1
  12. package/dist/containerContext.d.ts +2 -6
  13. package/dist/containerContext.d.ts.map +1 -1
  14. package/dist/containerContext.js +9 -8
  15. package/dist/containerContext.js.map +1 -1
  16. package/dist/deltaManager.d.ts.map +1 -1
  17. package/dist/deltaManager.js +13 -23
  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/dist/retriableDocumentStorageService.js +1 -1
  23. package/dist/retriableDocumentStorageService.js.map +1 -1
  24. package/lib/connectionManager.d.ts +2 -2
  25. package/lib/connectionManager.d.ts.map +1 -1
  26. package/lib/connectionManager.js +8 -12
  27. package/lib/connectionManager.js.map +1 -1
  28. package/lib/connectionStateHandler.d.ts +2 -3
  29. package/lib/connectionStateHandler.d.ts.map +1 -1
  30. package/lib/connectionStateHandler.js +9 -10
  31. package/lib/connectionStateHandler.js.map +1 -1
  32. package/lib/container.d.ts.map +1 -1
  33. package/lib/container.js +10 -9
  34. package/lib/container.js.map +1 -1
  35. package/lib/containerContext.d.ts +2 -6
  36. package/lib/containerContext.d.ts.map +1 -1
  37. package/lib/containerContext.js +9 -8
  38. package/lib/containerContext.js.map +1 -1
  39. package/lib/deltaManager.d.ts.map +1 -1
  40. package/lib/deltaManager.js +14 -24
  41. package/lib/deltaManager.js.map +1 -1
  42. package/lib/packageVersion.d.ts +1 -1
  43. package/lib/packageVersion.js +1 -1
  44. package/lib/packageVersion.js.map +1 -1
  45. package/lib/retriableDocumentStorageService.js +1 -1
  46. package/lib/retriableDocumentStorageService.js.map +1 -1
  47. package/package.json +7 -7
  48. package/src/connectionManager.ts +8 -15
  49. package/src/connectionStateHandler.ts +11 -12
  50. package/src/container.ts +10 -9
  51. package/src/containerContext.ts +10 -9
  52. package/src/deltaManager.ts +14 -26
  53. package/src/packageVersion.ts +1 -1
  54. package/src/retriableDocumentStorageService.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"retriableDocumentStorageService.js","sourceRoot":"","sources":["../src/retriableDocumentStorageService.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 { assert } from \"@fluidframework/common-utils\";\nimport { GenericError } from \"@fluidframework/container-utils\";\nimport {\n IDocumentStorageService,\n IDocumentStorageServicePolicies,\n ISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n ICreateBlobResponse,\n ISnapshotTree,\n ISummaryHandle,\n ISummaryTree,\n ITree,\n IVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { runWithRetry } from \"@fluidframework/driver-utils\";\n\nexport class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {\n private _disposed = false;\n constructor(\n private readonly internalStorageService: IDocumentStorageService,\n private readonly logger: ITelemetryLogger,\n ) {\n }\n\n public get policies(): IDocumentStorageServicePolicies | undefined {\n return this.internalStorageService.policies;\n }\n public get disposed() { return this._disposed; }\n public dispose() {\n this._disposed = true;\n }\n\n public get repositoryUrl(): string {\n return this.internalStorageService.repositoryUrl;\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n return this.runWithRetry(\n async () => this.internalStorageService.getSnapshotTree(version),\n \"storage_getSnapshotTree\",\n );\n }\n\n public async readBlob(id: string): Promise<ArrayBufferLike> {\n return this.runWithRetry(\n async () => this.internalStorageService.readBlob(id),\n \"storage_readBlob\",\n );\n }\n\n public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {\n return this.runWithRetry(\n async () => this.internalStorageService.getVersions(versionId, count),\n \"storage_getVersions\",\n );\n }\n\n public async write(tree: ITree, parents: string[], message: string, ref: string): Promise<IVersion> {\n return this.runWithRetry(\n async () => this.internalStorageService.write(tree, parents, message, ref),\n \"storage_write\",\n );\n }\n\n public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {\n // Not using retry loop here. Couple reasons:\n // 1. If client lost connectivity, then retry loop will result in uploading stale summary\n // by stale summarizer after connectivity comes back. It will cause failures for this client and for\n // real (new) summarizer. This problem in particular should be solved in future by supplying abort handle\n // on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity\n // 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary\n // upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take\n // retryAfter into account!\n // But retry loop is required for creation flow (Container.attach)\n assert((context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),\n 0x251 /* \"creation summary has to have seq=0 && handle === undefined\" */);\n if (context.referenceSequenceNumber !== 0) {\n return this.internalStorageService.uploadSummaryWithContext(summary, context);\n }\n\n // Creation flow with attachment blobs - need to do retries!\n return this.runWithRetry(\n async () => this.internalStorageService.uploadSummaryWithContext(summary, context),\n \"storage_uploadSummaryWithContext\",\n );\n }\n\n public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n return this.runWithRetry(\n async () => this.internalStorageService.downloadSummary(handle),\n \"storage_downloadSummary\",\n );\n }\n\n public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n return this.runWithRetry(\n async () => this.internalStorageService.createBlob(file),\n \"storage_createBlob\",\n );\n }\n\n private checkStorageDisposed() {\n if (this._disposed) {\n throw new GenericError(\"storageServiceDisposedCannotRetry\", { canRetry: false });\n }\n return undefined;\n }\n\n private async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {\n return runWithRetry(\n api,\n callName,\n this.logger,\n {\n retry: () => this.checkStorageDisposed(),\n },\n );\n }\n}\n"]}
1
+ {"version":3,"file":"retriableDocumentStorageService.js","sourceRoot":"","sources":["../src/retriableDocumentStorageService.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 { assert } from \"@fluidframework/common-utils\";\nimport { GenericError } from \"@fluidframework/container-utils\";\nimport {\n IDocumentStorageService,\n IDocumentStorageServicePolicies,\n ISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport {\n ICreateBlobResponse,\n ISnapshotTree,\n ISummaryHandle,\n ISummaryTree,\n ITree,\n IVersion,\n} from \"@fluidframework/protocol-definitions\";\nimport { IDisposable, ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { runWithRetry } from \"@fluidframework/driver-utils\";\n\nexport class RetriableDocumentStorageService implements IDocumentStorageService, IDisposable {\n private _disposed = false;\n constructor(\n private readonly internalStorageService: IDocumentStorageService,\n private readonly logger: ITelemetryLogger,\n ) {\n }\n\n public get policies(): IDocumentStorageServicePolicies | undefined {\n return this.internalStorageService.policies;\n }\n public get disposed() { return this._disposed; }\n public dispose() {\n this._disposed = true;\n }\n\n public get repositoryUrl(): string {\n return this.internalStorageService.repositoryUrl;\n }\n\n public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {\n return this.runWithRetry(\n async () => this.internalStorageService.getSnapshotTree(version),\n \"storage_getSnapshotTree\",\n );\n }\n\n public async readBlob(id: string): Promise<ArrayBufferLike> {\n return this.runWithRetry(\n async () => this.internalStorageService.readBlob(id),\n \"storage_readBlob\",\n );\n }\n\n public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {\n return this.runWithRetry(\n async () => this.internalStorageService.getVersions(versionId, count),\n \"storage_getVersions\",\n );\n }\n\n public async write(tree: ITree, parents: string[], message: string, ref: string): Promise<IVersion> {\n return this.runWithRetry(\n async () => this.internalStorageService.write(tree, parents, message, ref),\n \"storage_write\",\n );\n }\n\n public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {\n // Not using retry loop here. Couple reasons:\n // 1. If client lost connectivity, then retry loop will result in uploading stale summary\n // by stale summarizer after connectivity comes back. It will cause failures for this client and for\n // real (new) summarizer. This problem in particular should be solved in future by supplying abort handle\n // on all APIs and caller (ContainerRuntime.submitSummary) aborting call on loss of connectivity\n // 2. Similar, if we get 429 with retryAfter = 10 minutes, it's likely not the right call to retry summary\n // upload in 10 minutes - it's better to keep processing ops and retry later. Though caller needs to take\n // retryAfter into account!\n // But retry loop is required for creation flow (Container.attach)\n assert((context.referenceSequenceNumber === 0) === (context.ackHandle === undefined),\n 0x251 /* \"creation summary has to have seq=0 && handle === undefined\" */);\n if (context.referenceSequenceNumber !== 0) {\n return this.internalStorageService.uploadSummaryWithContext(summary, context);\n }\n\n // Creation flow with attachment blobs - need to do retries!\n return this.runWithRetry(\n async () => this.internalStorageService.uploadSummaryWithContext(summary, context),\n \"storage_uploadSummaryWithContext\",\n );\n }\n\n public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {\n return this.runWithRetry(\n async () => this.internalStorageService.downloadSummary(handle),\n \"storage_downloadSummary\",\n );\n }\n\n public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {\n return this.runWithRetry(\n async () => this.internalStorageService.createBlob(file),\n \"storage_createBlob\",\n );\n }\n\n private checkStorageDisposed() {\n if (this._disposed) {\n throw new GenericError(\"Storage Service is disposed. Cannot retry\", { canRetry: false });\n }\n return undefined;\n }\n\n private async runWithRetry<T>(api: () => Promise<T>, callName: string): Promise<T> {\n return runWithRetry(\n api,\n callName,\n this.logger,\n {\n retry: () => this.checkStorageDisposed(),\n },\n );\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/container-loader",
3
- "version": "0.57.0-51086",
3
+ "version": "0.58.0-55561",
4
4
  "description": "Fluid container loader",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": "https://github.com/microsoft/FluidFramework",
@@ -59,13 +59,13 @@
59
59
  "@fluidframework/common-definitions": "^0.20.1",
60
60
  "@fluidframework/common-utils": "^0.32.1",
61
61
  "@fluidframework/container-definitions": "^0.46.0-0",
62
- "@fluidframework/container-utils": "0.57.0-51086",
62
+ "@fluidframework/container-utils": "0.58.0-55561",
63
63
  "@fluidframework/core-interfaces": "^0.42.0",
64
- "@fluidframework/driver-definitions": "^0.44.0",
65
- "@fluidframework/driver-utils": "0.57.0-51086",
64
+ "@fluidframework/driver-definitions": "^0.45.0-0",
65
+ "@fluidframework/driver-utils": "0.58.0-55561",
66
66
  "@fluidframework/protocol-base": "^0.1034.0",
67
67
  "@fluidframework/protocol-definitions": "^0.1026.0",
68
- "@fluidframework/telemetry-utils": "0.57.0-51086",
68
+ "@fluidframework/telemetry-utils": "0.58.0-55561",
69
69
  "abort-controller": "^3.0.0",
70
70
  "double-ended-queue": "^2.1.0-0",
71
71
  "lodash": "^4.17.21",
@@ -74,8 +74,8 @@
74
74
  "devDependencies": {
75
75
  "@fluidframework/build-common": "^0.23.0",
76
76
  "@fluidframework/eslint-config-fluid": "^0.26.0-0",
77
- "@fluidframework/mocha-test-setup": "0.57.0-51086",
78
- "@fluidframework/test-loader-utils": "0.57.0-51086",
77
+ "@fluidframework/mocha-test-setup": "0.58.0-55561",
78
+ "@fluidframework/test-loader-utils": "0.58.0-55561",
79
79
  "@microsoft/api-extractor": "^7.16.1",
80
80
  "@rushstack/eslint-config": "^2.5.1",
81
81
  "@types/double-ended-queue": "^2.1.0",
@@ -67,17 +67,10 @@ const DefaultChunkSize = 16 * 1024;
67
67
  const fatalConnectErrorProp = { fatalConnectError: true };
68
68
 
69
69
  function getNackReconnectInfo(nackContent: INackContent) {
70
- // check message.content for Back-compat with old service.
71
- if (nackContent === undefined) {
72
- return createGenericNetworkError(
73
- "nackReasonUnknown", undefined, { canRetry: true }, { driverVersion: undefined });
74
- }
75
-
76
70
  const message = `Nack (${nackContent.type}): ${nackContent.message}`;
77
71
  const canRetry = nackContent.code !== 403;
78
72
  const retryAfterMs = nackContent.retryAfter !== undefined ? nackContent.retryAfter * 1000 : undefined;
79
73
  return createGenericNetworkError(
80
- `nack [${nackContent.code}]`,
81
74
  message,
82
75
  { canRetry, retryAfterMs },
83
76
  { statusCode: nackContent.code, driverVersion: undefined });
@@ -688,7 +681,7 @@ export class ConnectionManager implements IConnectionManager {
688
681
  }
689
682
 
690
683
  /**
691
- * Disconnect the current connection and reconnect.
684
+ * Disconnect the current connection and reconnect. Closes the container if it fails.
692
685
  * @param connection - The connection that wants to reconnect - no-op if it's different from this.connection
693
686
  * @param requestedMode - Read or write
694
687
  * @param error - Error reconnect information including whether or not to reconnect
@@ -698,11 +691,11 @@ export class ConnectionManager implements IConnectionManager {
698
691
  requestedMode: ConnectionMode,
699
692
  error: IAnyDriverError,
700
693
  ) {
701
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
702
- this.reconnectOnErrorCore(
694
+ this.reconnect(
703
695
  requestedMode,
704
696
  error.message,
705
- error);
697
+ error)
698
+ .catch(this.props.closeHandler);
706
699
  }
707
700
 
708
701
  /**
@@ -712,7 +705,7 @@ export class ConnectionManager implements IConnectionManager {
712
705
  * @param error - Error reconnect information including whether or not to reconnect
713
706
  * @returns A promise that resolves when the connection is reestablished or we stop trying
714
707
  */
715
- private async reconnectOnErrorCore(
708
+ private async reconnect(
716
709
  requestedMode: ConnectionMode,
717
710
  disconnectMessage: string,
718
711
  error?: IAnyDriverError,
@@ -812,7 +805,7 @@ export class ConnectionManager implements IConnectionManager {
812
805
  this.pendingReconnect = true;
813
806
  Promise.resolve().then(async () => {
814
807
  if (this.pendingReconnect) { // still valid?
815
- await this.reconnectOnErrorCore(
808
+ await this.reconnect(
816
809
  "write", // connectionMode
817
810
  "Switch to write", // message
818
811
  );
@@ -863,10 +856,9 @@ export class ConnectionManager implements IConnectionManager {
863
856
  // Always connect in write mode after getting nacked.
864
857
  private readonly nackHandler = (documentId: string, messages: INack[]) => {
865
858
  const message = messages[0];
866
- // TODO: we should remove this check when service updates?
867
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
868
859
  if (this._readonlyPermissions) {
869
860
  this.props.closeHandler(createWriteError("writeOnReadOnlyDocument", { driverVersion: undefined }));
861
+ return
870
862
  }
871
863
 
872
864
  const reconnectInfo = getNackReconnectInfo(message.content);
@@ -874,6 +866,7 @@ export class ConnectionManager implements IConnectionManager {
874
866
  // If the nack indicates we cannot retry, then close the container outright
875
867
  if (!reconnectInfo.canRetry) {
876
868
  this.props.closeHandler(reconnectInfo);
869
+ return;
877
870
  }
878
871
 
879
872
  this.reconnectOnError(
@@ -5,14 +5,13 @@
5
5
 
6
6
  import { ITelemetryLogger } from "@fluidframework/common-definitions";
7
7
  import { IConnectionDetails } from "@fluidframework/container-definitions";
8
- import { ProtocolOpHandler } from "@fluidframework/protocol-base";
9
- import { ConnectionMode, ISequencedClient } from "@fluidframework/protocol-definitions";
8
+ import { ConnectionMode, IQuorumClients, ISequencedClient } from "@fluidframework/protocol-definitions";
10
9
  import { PerformanceEvent } from "@fluidframework/telemetry-utils";
11
10
  import { assert, Timer } from "@fluidframework/common-utils";
12
11
  import { ConnectionState } from "./container";
13
12
 
14
13
  export interface IConnectionStateHandler {
15
- protocolHandler: () => ProtocolOpHandler | undefined,
14
+ quorumClients: () => IQuorumClients | undefined,
16
15
  logConnectionStateChangeTelemetry:
17
16
  (value: ConnectionState, oldState: ConnectionState, reason?: string | undefined) => void,
18
17
  shouldClientJoinWrite: () => boolean,
@@ -129,14 +128,14 @@ export class ConnectionStateHandler {
129
128
  }
130
129
 
131
130
  private applyForConnectedState(source: "removeMemberEvent" | "addMemberEvent" | "timeout" | "containerSaved") {
132
- const protocolHandler = this.handler.protocolHandler();
133
- assert(protocolHandler !== undefined, 0x236 /* "In all cases it should be already installed" */);
131
+ const quorumClients = this.handler.quorumClients();
132
+ assert(quorumClients !== undefined, 0x236 /* "In all cases it should be already installed" */);
134
133
  // Move to connected state only if we are in Connecting state, we have seen our join op
135
134
  // and there is no timer running which means we are not waiting for previous client to leave
136
135
  // or timeout has occured while doing so.
137
136
  if (this.pendingClientId !== this.clientId
138
137
  && this.pendingClientId !== undefined
139
- && protocolHandler.quorum.getMember(this.pendingClientId) !== undefined
138
+ && quorumClients.getMember(this.pendingClientId) !== undefined
140
139
  && !this.prevClientLeftTimer.hasTimer
141
140
  ) {
142
141
  this.waitEvent?.end({ source });
@@ -150,8 +149,8 @@ export class ConnectionStateHandler {
150
149
  pendingClientId: this.pendingClientId,
151
150
  clientId: this.clientId,
152
151
  hasTimer: this.prevClientLeftTimer.hasTimer,
153
- inQuorum: protocolHandler !== undefined && this.pendingClientId !== undefined
154
- && protocolHandler.quorum.getMember(this.pendingClientId) !== undefined,
152
+ inQuorum: quorumClients !== undefined && this.pendingClientId !== undefined
153
+ && quorumClients.getMember(this.pendingClientId) !== undefined,
155
154
  });
156
155
  }
157
156
  }
@@ -189,13 +188,13 @@ export class ConnectionStateHandler {
189
188
  // Report telemetry after we set client id, but before transitioning to Connected state below!
190
189
  this.handler.logConnectionStateChangeTelemetry(ConnectionState.Connecting, oldState);
191
190
 
192
- const protocolHandler = this.handler.protocolHandler();
191
+ const quorumClients = this.handler.quorumClients();
193
192
  // Check if we already processed our own join op through delta storage!
194
193
  // we are fetching ops from storage in parallel to connecting to ordering service
195
194
  // Given async processes, it's possible that we have already processed our own join message before
196
195
  // connection was fully established.
197
196
  // Note that we might be still initializing quorum - connection is established proactively on load!
198
- if ((protocolHandler !== undefined && protocolHandler.quorum.getMember(details.clientId) !== undefined)
197
+ if ((quorumClients !== undefined && quorumClients.getMember(details.clientId) !== undefined)
199
198
  || connectionMode === "read"
200
199
  ) {
201
200
  assert(!this.prevClientLeftTimer.hasTimer, 0x2a6 /* "there should be no timer for 'read' connections" */);
@@ -216,10 +215,10 @@ export class ConnectionStateHandler {
216
215
 
217
216
  const oldState = this._connectionState;
218
217
  this._connectionState = value;
219
- const quorum = this.handler.protocolHandler()?.quorum;
218
+ const quorumClients = this.handler.quorumClients();
220
219
  let client: ILocalSequencedClient | undefined;
221
220
  if (this._clientId !== undefined) {
222
- client = quorum?.getMember(this._clientId);
221
+ client = quorumClients?.getMember(this._clientId);
223
222
  }
224
223
  if (value === ConnectionState.Connected) {
225
224
  assert(oldState === ConnectionState.Connecting,
package/src/container.ts CHANGED
@@ -258,7 +258,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
258
258
  const mode: IContainerLoadMode = loadOptions.loadMode ?? defaultMode;
259
259
 
260
260
  const onClosed = (err?: ICriticalContainerError) => {
261
- reject(err ?? new GenericError("containerClosedWithoutErrorDuringLoad"));
261
+ reject(err ?? new GenericError("Container closed without error during load"));
262
262
  };
263
263
  container.on("closed", onClosed);
264
264
 
@@ -562,6 +562,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
562
562
  error: {
563
563
  // load information to associate errors with the specific load point
564
564
  dmInitialSeqNumber: () => this._deltaManager?.initialSequenceNumber,
565
+ dmLastProcessedSeqNumber: () => this._deltaManager?.lastSequenceNumber,
565
566
  dmLastKnownSeqNumber: () => this._deltaManager?.lastKnownSeqNumber,
566
567
  containerLoadedFromVersionId: () => this.loadedFromVersion?.id,
567
568
  containerLoadedFromVersionDate: () => this.loadedFromVersion?.date,
@@ -588,7 +589,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
588
589
 
589
590
  this.connectionStateHandler = new ConnectionStateHandler(
590
591
  {
591
- protocolHandler: () => this._protocolHandler,
592
+ quorumClients: () => this._protocolHandler?.quorum,
592
593
  logConnectionStateChangeTelemetry: (value, oldState, reason) =>
593
594
  this.logConnectionStateChangeTelemetry(value, oldState, reason),
594
595
  shouldClientJoinWrite: () => this._deltaManager.connectionManager.shouldJoinWrite(),
@@ -779,7 +780,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
779
780
  public async attach(request: IRequest): Promise<void> {
780
781
  await PerformanceEvent.timedExecAsync(this.mc.logger, { eventName: "Attach" }, async () => {
781
782
  if (this._lifecycleState !== "loaded") {
782
- throw new UsageError(`containerNotValidForAttach [${this._lifecycleState}]`);
783
+ throw new UsageError(`The Container is not in a valid state for attach [${this._lifecycleState}]`);
783
784
  }
784
785
 
785
786
  // If container is already attached or attach is in progress, throw an error.
@@ -1013,7 +1014,7 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1013
1014
  return;
1014
1015
  }
1015
1016
 
1016
- this.close(new GenericError("existingContextDoesNotSatisfyIncomingProposal"));
1017
+ this.close(new GenericError("Existing context does not satisfy incoming proposal"));
1017
1018
  }
1018
1019
 
1019
1020
  private async getVersion(version: string | null): Promise<IVersion | undefined> {
@@ -1636,17 +1637,17 @@ export class Container extends EventEmitterWithErrorHandling<IContainerEvents> i
1636
1637
  // Check and report if we're getting messages from a clientId that we previously
1637
1638
  // flagged as shouldHaveLeft, or from a client that's not in the quorum but should be
1638
1639
  if (message.clientId != null) {
1639
- let errorCode: string | undefined;
1640
+ let errorMsg: string | undefined;
1640
1641
  const client: ILocalSequencedClient | undefined =
1641
1642
  this.getQuorum().getMember(message.clientId);
1642
1643
  if (client === undefined && message.type !== MessageType.ClientJoin) {
1643
- errorCode = "messageClientIdMissingFromQuorum";
1644
+ errorMsg = "Remote message's clientId is missing from the quorum";
1644
1645
  } else if (client?.shouldHaveLeft === true && message.type !== MessageType.NoOp) {
1645
- errorCode = "messageClientIdShouldHaveLeft";
1646
+ errorMsg = "Remote message's clientId already should have left";
1646
1647
  }
1647
- if (errorCode !== undefined) {
1648
+ if (errorMsg !== undefined) {
1648
1649
  const error = new DataCorruptionError(
1649
- errorCode,
1650
+ errorMsg,
1650
1651
  extractSafePropertiesFromMessage(message));
1651
1652
  this.close(normalizeError(error));
1652
1653
  }
@@ -44,6 +44,7 @@ import {
44
44
  import { PerformanceEvent } from "@fluidframework/telemetry-utils";
45
45
  import { assert, LazyPromise } from "@fluidframework/common-utils";
46
46
  import { Container } from "./container";
47
+ import { isFluidResolvedUrl } from "@fluidframework/driver-utils";
47
48
  import { ICodeDetailsLoader, IFluidModuleWithDetails } from "./loader";
48
49
 
49
50
  const PackageNotFactoryError = "Code package does not implement IRuntimeFactory";
@@ -90,19 +91,19 @@ export class ContainerContext implements IContainerContext {
90
91
 
91
92
  public readonly taggedLogger: ITelemetryLogger;
92
93
 
93
- /**
94
- * Subtlety: returns this.taggedLogger since vanilla this.logger is now deprecated. See IContainerContext for more
95
- * details.
96
- */
97
- /** @deprecated See IContainerContext for more details. */
98
- public get logger(): ITelemetryLogger {
99
- return this.taggedLogger;
100
- }
101
-
102
94
  public get clientId(): string | undefined {
103
95
  return this.container.clientId;
104
96
  }
105
97
 
98
+ /** @deprecated Added back to unblock 0.56 integration */
99
+ public get id(): string {
100
+ const resolvedUrl = this.container.resolvedUrl;
101
+ if (isFluidResolvedUrl(resolvedUrl)) {
102
+ return resolvedUrl.id;
103
+ }
104
+ return "";
105
+ }
106
+
106
107
  public get clientDetails(): IClientDetails {
107
108
  return this.container.clientDetails;
108
109
  }
@@ -37,7 +37,6 @@ import {
37
37
  ISequencedDocumentMessage,
38
38
  ISignalMessage,
39
39
  MessageType,
40
- ITrace,
41
40
  ConnectionMode,
42
41
  } from "@fluidframework/protocol-definitions";
43
42
  import {
@@ -45,15 +44,16 @@ import {
45
44
  } from "@fluidframework/driver-utils";
46
45
  import {
47
46
  ThrottlingWarning,
48
- CreateProcessingError,
49
47
  DataCorruptionError,
50
48
  extractSafePropertiesFromMessage,
49
+ DataProcessingError,
51
50
  } from "@fluidframework/container-utils";
52
51
  import { DeltaQueue } from "./deltaQueue";
53
52
  import {
54
53
  IConnectionManagerFactoryArgs,
55
54
  IConnectionManager,
56
55
  } from "./contracts";
56
+ import { TelemetryDataTag } from "@fluidframework/telemetry-utils";
57
57
 
58
58
  export interface IConnectionArgs {
59
59
  mode?: ConnectionMode;
@@ -184,19 +184,11 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
184
184
  public get clientDetails() { return this.connectionManager.clientDetails; }
185
185
 
186
186
  public submit(type: MessageType, contents: any, batch = false, metadata?: any) {
187
- // Start adding trace for the op.
188
- const traces: ITrace[] = [
189
- {
190
- action: "start",
191
- service: "client",
192
- timestamp: Date.now(),
193
- }];
194
187
 
195
188
  const messagePartial: Omit<IDocumentMessage, "clientSequenceNumber"> = {
196
189
  contents: JSON.stringify(contents),
197
190
  metadata,
198
191
  referenceSequenceNumber: this.lastProcessedSequenceNumber,
199
- traces,
200
192
  type,
201
193
  };
202
194
 
@@ -297,7 +289,8 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
297
289
  });
298
290
 
299
291
  this._inbound.on("error", (error) => {
300
- this.close(CreateProcessingError(error, "deltaManagerInboundErrorHandler", this.lastMessage));
292
+ this.close(
293
+ DataProcessingError.wrapIfUnrecognized(error, "deltaManagerInboundErrorHandler", this.lastMessage));
301
294
  });
302
295
 
303
296
  // Inbound signal queue
@@ -583,9 +576,13 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
583
576
  // DeltaManager overall policy - drop all ops on disconnection and rely on
584
577
  // container runtime to deal with resubmitting any ops that did not make it through.
585
578
  // So drop them, but also raise error event to look into details.
586
- this.logger.sendErrorEvent({
579
+ this.logger.sendTelemetryEvent({
587
580
  eventName: "OpenBatchOnDisconnect",
588
581
  length: this.messageBuffer.length,
582
+ reason: {
583
+ value: reason,
584
+ tag: TelemetryDataTag.PackageData,
585
+ }
589
586
  });
590
587
  this.messageBuffer.length = 0;
591
588
  }
@@ -606,7 +603,6 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
606
603
 
607
604
  const throttlingWarning: IThrottlingWarning = ThrottlingWarning.wrap(
608
605
  error,
609
- "deltaManagerEmitDelayInfo",
610
606
  delayMs / 1000 /* retryAfterSeconds */,
611
607
  this.logger,
612
608
  );
@@ -727,9 +723,10 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
727
723
  const message1 = this.comparableMessagePayload(this.previouslyProcessedMessage);
728
724
  const message2 = this.comparableMessagePayload(message);
729
725
  if (message1 !== message2) {
726
+ // This looks like a data corruption but the culprit has been found instead
727
+ // to be the file being overwritten in storage. See PR #5882.
730
728
  const error = new NonRetryableError(
731
- "twoMessagesWithSameSeqNumAndDifferentPayload",
732
- undefined,
729
+ "Found two messages with the same sequenceNumber but different payloads",
733
730
  DriverErrorType.fileOverwrittenInStorage,
734
731
  {
735
732
  clientId: this.connectionManager.clientId,
@@ -781,18 +778,9 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
781
778
 
782
779
  this.connectionManager.beforeProcessingIncomingOp(message);
783
780
 
784
- // Add final ack trace.
785
- if (message.traces !== undefined && message.traces.length > 0) {
786
- message.traces.push({
787
- action: "end",
788
- service: "client",
789
- timestamp: Date.now(),
790
- });
791
- }
792
-
793
781
  // Watch the minimum sequence number and be ready to update as needed
794
782
  if (this.minSequenceNumber > message.minimumSequenceNumber) {
795
- throw new DataCorruptionError("msnMovesBackwards", {
783
+ throw new DataCorruptionError("Found a lower minimumSequenceNumber (msn) than previously recorded", {
796
784
  ...extractSafePropertiesFromMessage(message),
797
785
  clientId: this.connectionManager.clientId,
798
786
  });
@@ -800,7 +788,7 @@ export class DeltaManager<TConnectionManager extends IConnectionManager>
800
788
  this.minSequenceNumber = message.minimumSequenceNumber;
801
789
 
802
790
  if (message.sequenceNumber !== this.lastProcessedSequenceNumber + 1) {
803
- throw new DataCorruptionError("nonSequentialSequenceNumber", {
791
+ throw new DataCorruptionError("Found a non-Sequential sequenceNumber", {
804
792
  ...extractSafePropertiesFromMessage(message),
805
793
  clientId: this.connectionManager.clientId,
806
794
  });
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/container-loader";
9
- export const pkgVersion = "0.57.0-51086";
9
+ export const pkgVersion = "0.58.0-55561";
@@ -108,7 +108,7 @@ export class RetriableDocumentStorageService implements IDocumentStorageService,
108
108
 
109
109
  private checkStorageDisposed() {
110
110
  if (this._disposed) {
111
- throw new GenericError("storageServiceDisposedCannotRetry", { canRetry: false });
111
+ throw new GenericError("Storage Service is disposed. Cannot retry", { canRetry: false });
112
112
  }
113
113
  return undefined;
114
114
  }