From 26fcaf4e74ff4693a3d0dc072f286e0fafaa84ef Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Thu, 10 Mar 2022 15:21:47 -0500 Subject: [PATCH 01/14] add connect(), disconnect(), deprecate setAutoReconnect, connected, resume --- api-report/container-loader.api.md | 4 + api-report/fluid-static.api.md | 13 ++++ .../api-report/container-definitions.api.md | 7 +- .../lib/container-definitions/src/loader.ts | 21 +++++- .../fluid-static/src/fluidContainer.ts | 40 ++++++++++ .../loader/container-loader/src/container.ts | 74 ++++++++++++++++++- 6 files changed, 154 insertions(+), 5 deletions(-) diff --git a/api-report/container-loader.api.md b/api-report/container-loader.api.md index f574f82b5a80..31002cfe08f3 100644 --- a/api-report/container-loader.api.md +++ b/api-report/container-loader.api.md @@ -67,12 +67,16 @@ export class Container extends EventEmitterWithErrorHandling i // (undocumented) get closed(): boolean; // (undocumented) + connect(): void; + // (undocumented) get connected(): boolean; // (undocumented) get connectionState(): ConnectionState; static createDetached(loader: Loader, codeDetails: IFluidCodeDetails): Promise; // (undocumented) get deltaManager(): IDeltaManager; + // (undocumented) + disconnect(): void; forceReadonly(readonly: boolean): void; // (undocumented) getAbsoluteUrl(relativeUrl: string): Promise; diff --git a/api-report/fluid-static.api.md b/api-report/fluid-static.api.md index a1dcbbdafe5e..bfcf590369c4 100644 --- a/api-report/fluid-static.api.md +++ b/api-report/fluid-static.api.md @@ -18,6 +18,16 @@ import { IFluidDataStoreFactory } from '@fluidframework/runtime-definitions'; import { IFluidLoadable } from '@fluidframework/core-interfaces'; import { TypedEventEmitter } from '@fluidframework/common-utils'; +// @public +export namespace ConnectionState { + export type Connected = 2; + export type Connecting = 1; + export type Disconnected = 0; +} + +// @public +export type ConnectionState = ConnectionState.Disconnected | ConnectionState.Connecting | ConnectionState.Connected; + // @public export interface ContainerSchema { dynamicObjectTypes?: LoadableObjectClass[]; @@ -42,6 +52,7 @@ export class FluidContainer extends TypedEventEmitter imp attach(): Promise; get attachState(): AttachState; get connected(): boolean; + get connectionState(): ConnectionState; create(objectClass: LoadableObjectClass): Promise; dispose(): void; get disposed(): boolean; @@ -59,7 +70,9 @@ export interface IConnection { export interface IFluidContainer extends IEventProvider { attach(): Promise; readonly attachState: AttachState; + // @deprecated readonly connected: boolean; + readonly connectionState: ConnectionState; create(objectClass: LoadableObjectClass): Promise; dispose(): void; readonly disposed: boolean; diff --git a/common/lib/container-definitions/api-report/container-definitions.api.md b/common/lib/container-definitions/api-report/container-definitions.api.md index db89125d6997..d3546b70b2dc 100644 --- a/common/lib/container-definitions/api-report/container-definitions.api.md +++ b/common/lib/container-definitions/api-report/container-definitions.api.md @@ -134,9 +134,12 @@ export interface IContainer extends IEventProvider, IFluidRout close(error?: ICriticalContainerError): void; closeAndGetPendingLocalState(): string; readonly closed: boolean; + connect?(): void; + // @deprecated readonly connected: boolean; readonly connectionState: ConnectionState; deltaManager: IDeltaManager; + disconnect?(): void; // @alpha forceReadonly?(readonly: boolean): any; getAbsoluteUrl(relativeUrl: string): Promise; @@ -148,10 +151,10 @@ export interface IContainer extends IEventProvider, IFluidRout readonly readOnlyInfo: ReadOnlyInfo; request(request: IRequest): Promise; resolvedUrl: IResolvedUrl | undefined; - // @alpha + // @deprecated resume?(): void; serialize(): string; - // @alpha + // @deprecated setAutoReconnect?(reconnect: boolean): void; } diff --git a/common/lib/container-definitions/src/loader.ts b/common/lib/container-definitions/src/loader.ts index 932122c2b66b..3934f405414d 100644 --- a/common/lib/container-definitions/src/loader.ts +++ b/common/lib/container-definitions/src/loader.ts @@ -252,20 +252,37 @@ export interface IContainer extends IEventProvider, IFluidRout /** * Boolean indicating whether the container is currently connected or not + * @deprecated - 0.58, This API will be removed in 0.60 + * Use `connectionState` instead + * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ readonly connected: boolean; + /** + * Try to connect the container to the delta stream + */ + connect?(): void; + + /** + * Disconnect the container from the delta stream + */ + disconnect?(): void; + /** * Dictates whether or not the current container will automatically attempt to reconnect to the delta stream * after receiving a disconnect event * @param reconnect - Boolean indicating if reconnect should automatically occur - * @alpha + * @deprecated - 0.58.1, This API will be removed in 0.59.0 + * Use `connect()` and `disconnect()` instead + * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ setAutoReconnect?(reconnect: boolean): void; /** * Have the container attempt to resume processing ops - * @alpha + * @deprecated - 0.58.1, This API will be removed in 0.59.0 + * Use `connect()` instead + * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ resume?(): void; diff --git a/packages/framework/fluid-static/src/fluidContainer.ts b/packages/framework/fluid-static/src/fluidContainer.ts index 2d115acb7816..43c96ed4027c 100644 --- a/packages/framework/fluid-static/src/fluidContainer.ts +++ b/packages/framework/fluid-static/src/fluidContainer.ts @@ -67,6 +67,31 @@ export interface IFluidContainerEvents extends IEvent { (event: "connected" | "dispose" | "disconnected" | "saved" | "dirty", listener: () => void): void; } +/** + * Namespace for the different connection states a container can be in + */ + export namespace ConnectionState { + /** + * The document is no longer connected to the delta server + */ + export type Disconnected = 0; + + /** + * The document has an inbound connection but is still pending for outbound deltas + */ + export type Connecting = 1; + + /** + * The document is fully connected + */ + export type Connected = 2; +} + +/** + * Type defining the different states of connectivity a container can be in + */ +export type ConnectionState = ConnectionState.Disconnected | ConnectionState.Connecting | ConnectionState.Connected; + /** * The IFluidContainer provides an entrypoint into the client side of collaborative Fluid data. It provides access * to the data as well as status on the collaboration session. @@ -74,9 +99,17 @@ export interface IFluidContainerEvents extends IEvent { export interface IFluidContainer extends IEventProvider { /** * Whether the container is connected to the collaboration session. + * @deprecated - 0.58.1, This API will be removed in 0.59.0 + * Use `connectionState` instead + * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ readonly connected: boolean; + /** + * Provides the current connected state of the container + */ + readonly connectionState: ConnectionState; + /** * A container is considered **dirty** if it has local changes that have not yet been acknowledged by the service. * You should always check the `isDirty` flag before closing the container or navigating away from the page. @@ -184,6 +217,13 @@ export class FluidContainer extends TypedEventEmitter imp return this.container.connected; } + /** + * {@inheritDoc IFluidContainer.connectionState} + */ + public get connectionState(): ConnectionState { + return this.container.connectionState; + } + /** * {@inheritDoc IFluidContainer.initialObjects} */ diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index dc1d006adf77..4c8bc44a1aab 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -935,6 +935,78 @@ export class Container extends EventEmitterWithErrorHandling i } } + public connect() { + if (!this.closed && !this.connected) { + // Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler(). + // If there is gap, we will learn about it once connected, but the gap should be small (if any), + // assuming that connect() is called quickly after initial container boot. + this.connectInternal({ reason: "DocumentOpenResume", fetchOpsFromStorage: false }); + } + } + + private connectInternal(args: IConnectionArgs) { + assert(!this.closed, "Attempting to connect() a closed DeltaManager"); + + // Resume processing ops + if (!this.resumedOpProcessingAfterLoad) { + this.resumedOpProcessingAfterLoad = true; + this._deltaManager.inbound.resume(); + this._deltaManager.inboundSignal.resume(); + } + + // Ensure connection to web socket + this.connectToDeltaStream(args); + + const mode = ReconnectMode.Enabled; + const currentMode = this._deltaManager.connectionManager.reconnectMode; + + // Set Auto Reconnect Mode + if (currentMode !== mode) { + const now = performance.now(); + const duration = now - this.setAutoReconnectTime; + this.setAutoReconnectTime = now; + + this.mc.logger.sendTelemetryEvent({ + eventName: "AutoReconnectEnabled", + connectionMode: this.connectionMode, + connectionState: ConnectionState[this.connectionState], + duration, + }); + + this._deltaManager.connectionManager.setAutoReconnect(mode); + } + } + + public disconnect() { + if (!this.closed && this.connected) { + this.disconnectInternal(); + } + } + + private disconnectInternal() { + assert(!this.closed, "Attempting to disconnect() a closed DeltaManager"); + + const mode = ReconnectMode.Disabled; + const currentMode = this._deltaManager.connectionManager.reconnectMode; + + // Set Auto Reconnect Mode + if (currentMode !== mode) { + const now = performance.now(); + const duration = now - this.setAutoReconnectTime; + this.setAutoReconnectTime = now; + + this.mc.logger.sendTelemetryEvent({ + eventName: "AutoReconnectDisabled", + connectionMode: this.connectionMode, + connectionState: ConnectionState[this.connectionState], + duration, + }); + + // ConnectionManager will handle disconnecting the container + this._deltaManager.connectionManager.setAutoReconnect(mode); + } + } + public resume() { if (!this.closed) { // Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler(). @@ -1139,7 +1211,7 @@ export class Container extends EventEmitterWithErrorHandling i switch (loadMode.deltaConnection) { case undefined: - this.resume(); + this.connect(); break; case "delayed": this.resumedOpProcessingAfterLoad = true; From 1126595a94db5f082f3733cb4835a489779d0e26 Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Thu, 10 Mar 2022 15:26:20 -0500 Subject: [PATCH 02/14] revert this.connect() to resume() --- packages/loader/container-loader/src/container.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index 4c8bc44a1aab..861fb81b9242 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -1211,7 +1211,7 @@ export class Container extends EventEmitterWithErrorHandling i switch (loadMode.deltaConnection) { case undefined: - this.connect(); + this.resume(); break; case "delayed": this.resumedOpProcessingAfterLoad = true; From 8b2e788d4440baa23680b1caa029486abe88baaf Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Fri, 11 Mar 2022 11:40:16 -0500 Subject: [PATCH 03/14] remove connect/disconncet from IContainer, reuse ConnectionState from container-definitions, dont use this.connected --- .../lib/container-definitions/src/loader.ts | 10 ------- .../fluid-static/src/fluidContainer.ts | 27 +------------------ .../loader/container-loader/src/container.ts | 2 +- 3 files changed, 2 insertions(+), 37 deletions(-) diff --git a/common/lib/container-definitions/src/loader.ts b/common/lib/container-definitions/src/loader.ts index 3934f405414d..98f057019423 100644 --- a/common/lib/container-definitions/src/loader.ts +++ b/common/lib/container-definitions/src/loader.ts @@ -258,16 +258,6 @@ export interface IContainer extends IEventProvider, IFluidRout */ readonly connected: boolean; - /** - * Try to connect the container to the delta stream - */ - connect?(): void; - - /** - * Disconnect the container from the delta stream - */ - disconnect?(): void; - /** * Dictates whether or not the current container will automatically attempt to reconnect to the delta stream * after receiving a disconnect event diff --git a/packages/framework/fluid-static/src/fluidContainer.ts b/packages/framework/fluid-static/src/fluidContainer.ts index 43c96ed4027c..aea95ce0ef83 100644 --- a/packages/framework/fluid-static/src/fluidContainer.ts +++ b/packages/framework/fluid-static/src/fluidContainer.ts @@ -5,7 +5,7 @@ import { TypedEventEmitter } from "@fluidframework/common-utils"; import { IFluidLoadable } from "@fluidframework/core-interfaces"; import { IEvent, IEventProvider } from "@fluidframework/common-definitions"; -import { AttachState, IContainer } from "@fluidframework/container-definitions"; +import { AttachState, IContainer, ConnectionState } from "@fluidframework/container-definitions"; import { LoadableObjectClass, LoadableObjectRecord } from "./types"; import { RootDataObject } from "./rootDataObject"; @@ -67,31 +67,6 @@ export interface IFluidContainerEvents extends IEvent { (event: "connected" | "dispose" | "disconnected" | "saved" | "dirty", listener: () => void): void; } -/** - * Namespace for the different connection states a container can be in - */ - export namespace ConnectionState { - /** - * The document is no longer connected to the delta server - */ - export type Disconnected = 0; - - /** - * The document has an inbound connection but is still pending for outbound deltas - */ - export type Connecting = 1; - - /** - * The document is fully connected - */ - export type Connected = 2; -} - -/** - * Type defining the different states of connectivity a container can be in - */ -export type ConnectionState = ConnectionState.Disconnected | ConnectionState.Connecting | ConnectionState.Connected; - /** * The IFluidContainer provides an entrypoint into the client side of collaborative Fluid data. It provides access * to the data as well as status on the collaboration session. diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index 861fb81b9242..fa360852fca9 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -978,7 +978,7 @@ export class Container extends EventEmitterWithErrorHandling i } public disconnect() { - if (!this.closed && this.connected) { + if (!this.closed && this.connectionState !== ConnectionState.Disconnected) { this.disconnectInternal(); } } From df6192c2e6650433a7598affb91e8c184858de8b Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Fri, 11 Mar 2022 11:52:13 -0500 Subject: [PATCH 04/14] update api-report --- api-report/fluid-static.api.md | 11 +---------- .../api-report/container-definitions.api.md | 2 -- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/api-report/fluid-static.api.md b/api-report/fluid-static.api.md index bfcf590369c4..24effa80ca90 100644 --- a/api-report/fluid-static.api.md +++ b/api-report/fluid-static.api.md @@ -6,6 +6,7 @@ import { AttachState } from '@fluidframework/container-definitions'; import { BaseContainerRuntimeFactory } from '@fluidframework/aqueduct'; +import { ConnectionState } from '@fluidframework/container-definitions'; import { DataObject } from '@fluidframework/aqueduct'; import { IAudience } from '@fluidframework/container-definitions'; import { IChannelFactory } from '@fluidframework/datastore-definitions'; @@ -18,16 +19,6 @@ import { IFluidDataStoreFactory } from '@fluidframework/runtime-definitions'; import { IFluidLoadable } from '@fluidframework/core-interfaces'; import { TypedEventEmitter } from '@fluidframework/common-utils'; -// @public -export namespace ConnectionState { - export type Connected = 2; - export type Connecting = 1; - export type Disconnected = 0; -} - -// @public -export type ConnectionState = ConnectionState.Disconnected | ConnectionState.Connecting | ConnectionState.Connected; - // @public export interface ContainerSchema { dynamicObjectTypes?: LoadableObjectClass[]; diff --git a/common/lib/container-definitions/api-report/container-definitions.api.md b/common/lib/container-definitions/api-report/container-definitions.api.md index d3546b70b2dc..d1748988790d 100644 --- a/common/lib/container-definitions/api-report/container-definitions.api.md +++ b/common/lib/container-definitions/api-report/container-definitions.api.md @@ -134,12 +134,10 @@ export interface IContainer extends IEventProvider, IFluidRout close(error?: ICriticalContainerError): void; closeAndGetPendingLocalState(): string; readonly closed: boolean; - connect?(): void; // @deprecated readonly connected: boolean; readonly connectionState: ConnectionState; deltaManager: IDeltaManager; - disconnect?(): void; // @alpha forceReadonly?(readonly: boolean): any; getAbsoluteUrl(relativeUrl: string): Promise; From 879400f10e85161fe430574aa679e951f0e03a89 Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Fri, 18 Mar 2022 14:52:23 -0400 Subject: [PATCH 05/14] assert attatch state is connected for connectInternal() --- packages/loader/container-loader/src/container.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index fa360852fca9..6fc94a9edbcd 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -946,6 +946,7 @@ export class Container extends EventEmitterWithErrorHandling i private connectInternal(args: IConnectionArgs) { assert(!this.closed, "Attempting to connect() a closed DeltaManager"); + assert(this._attachState === AttachState.Attached, "Attempting to connect() a container that is not attached"); // Resume processing ops if (!this.resumedOpProcessingAfterLoad) { From 11c7cd8ffe0c772a613542397272c29d8f3941a9 Mon Sep 17 00:00:00 2001 From: scottn12 Date: Fri, 1 Apr 2022 07:50:05 -0700 Subject: [PATCH 06/14] add broken types for fluid-static --- packages/framework/fluid-static/package.json | 13 +++++++++++-- .../src/test/types/validateFluidStaticPrevious.ts | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/framework/fluid-static/package.json b/packages/framework/fluid-static/package.json index fef250ddea0d..19a1f7112bac 100644 --- a/packages/framework/fluid-static/package.json +++ b/packages/framework/fluid-static/package.json @@ -72,6 +72,15 @@ }, "typeValidation": { "version": "0.58.3000", - "broken": {} + "broken": { + "0.58.2000": { + "ClassDeclaration_FluidContainer": { + "forwardCompat": false + }, + "InterfaceDeclaration_IFluidContainer": { + "forwardCompat": false + } + } + } } -} \ No newline at end of file +} diff --git a/packages/framework/fluid-static/src/test/types/validateFluidStaticPrevious.ts b/packages/framework/fluid-static/src/test/types/validateFluidStaticPrevious.ts index f4c279adf034..bd10805b56b9 100644 --- a/packages/framework/fluid-static/src/test/types/validateFluidStaticPrevious.ts +++ b/packages/framework/fluid-static/src/test/types/validateFluidStaticPrevious.ts @@ -96,6 +96,7 @@ declare function get_old_ClassDeclaration_FluidContainer(): declare function use_current_ClassDeclaration_FluidContainer( use: TypeOnly); use_current_ClassDeclaration_FluidContainer( + // @ts-expect-error compatibility expected to be broken get_old_ClassDeclaration_FluidContainer()); /* @@ -144,6 +145,7 @@ declare function get_old_InterfaceDeclaration_IFluidContainer(): declare function use_current_InterfaceDeclaration_IFluidContainer( use: TypeOnly); use_current_InterfaceDeclaration_IFluidContainer( + // @ts-expect-error compatibility expected to be broken get_old_InterfaceDeclaration_IFluidContainer()); /* From dd1a87252e35d5e8b8518da5a666d7030f068d7e Mon Sep 17 00:00:00 2001 From: scottn12 Date: Mon, 4 Apr 2022 10:46:36 -0700 Subject: [PATCH 07/14] add upcoming breaking changes, update deprecated messages, removed connectionState check for disconnect() --- BREAKING.md | 8 ++++++++ common/lib/container-definitions/src/loader.ts | 10 +++++----- packages/framework/fluid-static/src/fluidContainer.ts | 4 ++-- packages/loader/container-loader/src/container.ts | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/BREAKING.md b/BREAKING.md index 69b34d9aa269..a318b5b4cb1b 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -20,6 +20,8 @@ There are a few steps you can take to write a good change note and avoid needing - [Doing operations not allowed on deleted sub directory](#Doing-operations-not-allowed-on-deleted-sub-directory) - [IDirectory extends IDisposable](#IDirectory-extends-IDisposable) - [raiseContainerWarning removed from IContainerContext](#raiseContainerWarning-removed-from-IContainerContext) +- [connected deprecated from IContainer, IFluidContainer, and FluidContainer](#connected-deprecated-from-IContainer-IFluidContainer-and-FluidContainer) +- [setAutoReconnect and resume deprecated from IContainer and Container](#setAutoReconnect-and-resume-deprecated-from-IContainer-and-Container) ### Doing operations not allowed on deleted sub directory Users will not be allowed to do operations on a deleted directory. Users can subscribe to `disposed` event to know if a sub directory is deleted. Accessing deleted sub directory will throw `UsageError` exception now. @@ -30,6 +32,12 @@ IDirectory has started extending IDisposable. This means that users implementing ### raiseContainerWarning removed from IContainerContext `raiseContainerWarning` property will be removed from `IContainerContext` interface and `ContainerContext` class. Please refer to [raiseContainerWarning property](#Remove-raisecontainerwarning-property) for more details. +### connected deprecated from IContainer, IFluidContainer, and FluidContainer +`connected` has been deprecated from `IContainer`, `IFluidContainer`, and `FluidContainer`. It will be removed in a future major release. Use `connectionState.connected` property on the respective interfaces/classes instead. Please switch to the new APIs as soon as possible, and provide any feedback to the FluidFramework team if necessary. + +### setAutoReconnect and resume deprecated from IContainer and Container +`setAutoReconnect()` and `resume()` have been deprecated from `IContainer` and `Container`. They will be removed in a future major release. Use `connect()` instead of `setAutoReconnect(true)` and `resume()`, and use `disconnect()` instead of `setAutoReconnect(false)`. Please switch to the new APIs as soon as possible, and provide any feedback to the FluidFramework team if necessary. + ## 0.58 Breaking changes - [Move IntervalType from merge-tree to sequence package](#Move-IntervalType-from-merge-tree-to-sequence-package) - [Remove logger property from IContainerContext](#Remove-logger-property-from-IContainerContext) diff --git a/common/lib/container-definitions/src/loader.ts b/common/lib/container-definitions/src/loader.ts index 98f057019423..a7a07014a0c3 100644 --- a/common/lib/container-definitions/src/loader.ts +++ b/common/lib/container-definitions/src/loader.ts @@ -252,8 +252,8 @@ export interface IContainer extends IEventProvider, IFluidRout /** * Boolean indicating whether the container is currently connected or not - * @deprecated - 0.58, This API will be removed in 0.60 - * Use `connectionState` instead + * @deprecated - 0.58, This API will be removed in 0.60.0 + * Use `connectionState.connected` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ readonly connected: boolean; @@ -262,15 +262,15 @@ export interface IContainer extends IEventProvider, IFluidRout * Dictates whether or not the current container will automatically attempt to reconnect to the delta stream * after receiving a disconnect event * @param reconnect - Boolean indicating if reconnect should automatically occur - * @deprecated - 0.58.1, This API will be removed in 0.59.0 - * Use `connect()` and `disconnect()` instead + * @deprecated - 0.58, This API will be removed in 0.60.0 + * Use `connect()` and `disconnect()` instead of `setAutoReconnect(true)` and `setAutoReconnect(false)` respectively * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ setAutoReconnect?(reconnect: boolean): void; /** * Have the container attempt to resume processing ops - * @deprecated - 0.58.1, This API will be removed in 0.59.0 + * @deprecated - 0.58, This API will be removed in 0.60.0 * Use `connect()` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ diff --git a/packages/framework/fluid-static/src/fluidContainer.ts b/packages/framework/fluid-static/src/fluidContainer.ts index aea95ce0ef83..1613849fc5b9 100644 --- a/packages/framework/fluid-static/src/fluidContainer.ts +++ b/packages/framework/fluid-static/src/fluidContainer.ts @@ -74,8 +74,8 @@ export interface IFluidContainerEvents extends IEvent { export interface IFluidContainer extends IEventProvider { /** * Whether the container is connected to the collaboration session. - * @deprecated - 0.58.1, This API will be removed in 0.59.0 - * Use `connectionState` instead + * @deprecated - 0.58, This API will be removed in 0.60.0 + * Use `connectionState.Connected` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ readonly connected: boolean; diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index 1d1571fae1d3..4070bf1b7186 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -990,7 +990,7 @@ export class Container extends EventEmitterWithErrorHandling i } public disconnect() { - if (!this.closed && this.connectionState !== ConnectionState.Disconnected) { + if (!this.closed) { this.disconnectInternal(); } } From 5847ea074d921474085e95469321f703ec3c6ddc Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Mon, 4 Apr 2022 16:03:28 -0400 Subject: [PATCH 08/14] add connectionState diff to BREAKING.md --- BREAKING.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/BREAKING.md b/BREAKING.md index 5a838f708f48..4292c4fe5c03 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -37,7 +37,11 @@ IDirectory has started extending IDisposable. This means that users implementing `IContainerRuntimeBase.setFlushMode` is deprecated and will be removed in a future release. FlushMode will become an immutable property for the container runtime, optionally provided at creation time via the `IContainerRuntimeOptions` interface. See [#9480](https://github.com/microsoft/FluidFramework/issues/9480#issuecomment-1084790977) ### connected deprecated from IContainer, IFluidContainer, and FluidContainer -`connected` has been deprecated from `IContainer`, `IFluidContainer`, and `FluidContainer`. It will be removed in a future major release. Use `connectionState.connected` property on the respective interfaces/classes instead. Please switch to the new APIs as soon as possible, and provide any feedback to the FluidFramework team if necessary. +`connected` has been deprecated from `IContainer`, `IFluidContainer`, and `FluidContainer`. It will be removed in a future major release. Use `connectionState` property on the respective interfaces/classes instead. Please switch to the new APIs as soon as possible, and provide any feedback to the FluidFramework team if necessary. +``` diff +- if (fluidContainer.connected) ++ if (fluidContainer.connectionState === ConnectionState.Connected) +``` ### setAutoReconnect and resume deprecated from IContainer and Container `setAutoReconnect()` and `resume()` have been deprecated from `IContainer` and `Container`. They will be removed in a future major release. Use `connect()` instead of `setAutoReconnect(true)` and `resume()`, and use `disconnect()` instead of `setAutoReconnect(false)`. Please switch to the new APIs as soon as possible, and provide any feedback to the FluidFramework team if necessary. From 1ad180901f55520017f0daf36c40e74ee5be4f87 Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Mon, 4 Apr 2022 16:45:37 -0400 Subject: [PATCH 09/14] Update packages/framework/fluid-static/src/fluidContainer.ts Co-authored-by: Mark Fields --- packages/framework/fluid-static/src/fluidContainer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/fluid-static/src/fluidContainer.ts b/packages/framework/fluid-static/src/fluidContainer.ts index 1613849fc5b9..97b133b79253 100644 --- a/packages/framework/fluid-static/src/fluidContainer.ts +++ b/packages/framework/fluid-static/src/fluidContainer.ts @@ -75,7 +75,7 @@ export interface IFluidContainer extends IEventProvider { /** * Whether the container is connected to the collaboration session. * @deprecated - 0.58, This API will be removed in 0.60.0 - * Use `connectionState.Connected` instead + * Check `connectionState === ConnectionState.Connected` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ readonly connected: boolean; From a8c083b3ca739af7955ce7c1839b613160b9a6cb Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Tue, 5 Apr 2022 10:08:44 -0400 Subject: [PATCH 10/14] Update packages/loader/container-loader/src/container.ts Co-authored-by: Mark Fields --- packages/loader/container-loader/src/container.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index 4070bf1b7186..43c5cd5df893 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -996,7 +996,7 @@ export class Container extends EventEmitterWithErrorHandling i } private disconnectInternal() { - assert(!this.closed, "Attempting to disconnect() a closed DeltaManager"); + assert(!this.closed, "Attempting to disconnect() a closed Container"); const mode = ReconnectMode.Disabled; const currentMode = this._deltaManager.connectionManager.reconnectMode; From c6bbc9342a8fcc9f4ffbde7506a4c4f8b3a33a2c Mon Sep 17 00:00:00 2001 From: Scott Norton Date: Tue, 5 Apr 2022 10:08:55 -0400 Subject: [PATCH 11/14] Update common/lib/container-definitions/src/loader.ts Co-authored-by: Mark Fields --- common/lib/container-definitions/src/loader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/lib/container-definitions/src/loader.ts b/common/lib/container-definitions/src/loader.ts index a7a07014a0c3..680943f220da 100644 --- a/common/lib/container-definitions/src/loader.ts +++ b/common/lib/container-definitions/src/loader.ts @@ -253,7 +253,7 @@ export interface IContainer extends IEventProvider, IFluidRout /** * Boolean indicating whether the container is currently connected or not * @deprecated - 0.58, This API will be removed in 0.60.0 - * Use `connectionState.connected` instead + * Check `connectionState === ConnectionState.Connected` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ readonly connected: boolean; From 5a58350844c58f1dd7e2ef1c71dc496cffb86144 Mon Sep 17 00:00:00 2001 From: scottn12 Date: Tue, 5 Apr 2022 07:32:56 -0700 Subject: [PATCH 12/14] add @deprecated to Container class resume/setAutoReconnect --- api-report/container-loader.api.md | 4 ++-- .../loader/container-loader/src/container.ts | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/api-report/container-loader.api.md b/api-report/container-loader.api.md index 85d0c74fbca5..5d6db5af818a 100644 --- a/api-report/container-loader.api.md +++ b/api-report/container-loader.api.md @@ -104,13 +104,13 @@ export class Container extends EventEmitterWithErrorHandling i request(path: IRequest): Promise; // (undocumented) get resolvedUrl(): IResolvedUrl | undefined; - // (undocumented) + // @deprecated resume(): void; get scopes(): string[] | undefined; // (undocumented) serialize(): string; get serviceConfiguration(): IClientConfiguration | undefined; - // (undocumented) + // @deprecated setAutoReconnect(reconnect: boolean): void; // (undocumented) get storage(): IDocumentStorageService; diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index 43c5cd5df893..1b7b34259f33 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -909,6 +909,14 @@ export class Container extends EventEmitterWithErrorHandling i ); } + /** + * Dictates whether or not the current container will automatically attempt to reconnect to the delta stream + * after receiving a disconnect event + * @param reconnect - Boolean indicating if reconnect should automatically occur + * @deprecated - 0.58, This API will be removed in 0.60.0 + * Use `connect()` and `disconnect()` instead of `setAutoReconnect(true)` and `setAutoReconnect(false)` respectively + * See https://github.com/microsoft/FluidFramework/issues/9167 for context + */ public setAutoReconnect(reconnect: boolean) { if (this.closed) { throw new Error("Attempting to setAutoReconnect() a closed Container"); @@ -956,7 +964,7 @@ export class Container extends EventEmitterWithErrorHandling i } private connectInternal(args: IConnectionArgs) { - assert(!this.closed, "Attempting to connect() a closed DeltaManager"); + assert(!this.closed, "Attempting to connect() a closed Container"); assert(this._attachState === AttachState.Attached, "Attempting to connect() a container that is not attached"); // Resume processing ops @@ -1019,6 +1027,12 @@ export class Container extends EventEmitterWithErrorHandling i } } + /** + * Have the container attempt to resume processing ops + * @deprecated - 0.58, This API will be removed in 0.60.0 + * Use `connect()` instead + * See https://github.com/microsoft/FluidFramework/issues/9167 for context + */ public resume() { if (!this.closed) { // Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler(). From b7a4697c72c8389c1e4ea8ecb0bfbef6d8465c5f Mon Sep 17 00:00:00 2001 From: scottn12 Date: Tue, 5 Apr 2022 12:43:01 -0700 Subject: [PATCH 13/14] add to IContainer, update BREAKING.md, create setAutoReconnectInternal helper, add usageErrors --- BREAKING.md | 6 +- .../api-report/container-definitions.api.md | 2 + .../lib/container-definitions/src/loader.ts | 16 ++- .../fluid-static/src/fluidContainer.ts | 2 +- .../loader/container-loader/src/container.ts | 98 ++++++------------- 5 files changed, 53 insertions(+), 71 deletions(-) diff --git a/BREAKING.md b/BREAKING.md index 4292c4fe5c03..b0a05bc15aff 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -23,6 +23,7 @@ There are a few steps you can take to write a good change note and avoid needing - [`IContainerRuntimeBase.setFlushMode` is deprecated](#icontainerruntimebasesetflushmode-is-deprecated) - [connected deprecated from IContainer, IFluidContainer, and FluidContainer](#connected-deprecated-from-IContainer-IFluidContainer-and-FluidContainer) - [setAutoReconnect and resume deprecated from IContainer and Container](#setAutoReconnect-and-resume-deprecated-from-IContainer-and-Container) +- [IContainer.connect() and IContainer.disconnect() will be made mandatory in future major release](#icontainer-connect-and-icontainer-disconnect-will-be-made-mandatory-in-future-major-release) ### Doing operations not allowed on deleted sub directory Users will not be allowed to do operations on a deleted directory. Users can subscribe to `disposed` event to know if a sub directory is deleted. Accessing deleted sub directory will throw `UsageError` exception now. @@ -44,7 +45,10 @@ IDirectory has started extending IDisposable. This means that users implementing ``` ### setAutoReconnect and resume deprecated from IContainer and Container -`setAutoReconnect()` and `resume()` have been deprecated from `IContainer` and `Container`. They will be removed in a future major release. Use `connect()` instead of `setAutoReconnect(true)` and `resume()`, and use `disconnect()` instead of `setAutoReconnect(false)`. Please switch to the new APIs as soon as possible, and provide any feedback to the FluidFramework team if necessary. +`setAutoReconnect()` and `resume()` have been deprecated from `IContainer` and `Container`. They will be removed in a future major release. Use `connect()` instead of `setAutoReconnect(true)` and `resume()`, and use `disconnect()` instead of `setAutoReconnect(false)`. Note, when using these new functions you will need to ensure that the container is both attached and not closed to prevent an error being thrown. Please switch to the new APIs as soon as possible, and provide any feedback to the FluidFramework team if necessary. + +### IContainer.connect() and IContainer.disconnect() will be made mandatory in future major release +In major release 1.0, the optional functions `IContainer.connect()` `IContainer.disconnect()` will be made mandatory functions. ## 0.58 Breaking changes - [Move IntervalType from merge-tree to sequence package](#Move-IntervalType-from-merge-tree-to-sequence-package) diff --git a/common/lib/container-definitions/api-report/container-definitions.api.md b/common/lib/container-definitions/api-report/container-definitions.api.md index d1748988790d..d3546b70b2dc 100644 --- a/common/lib/container-definitions/api-report/container-definitions.api.md +++ b/common/lib/container-definitions/api-report/container-definitions.api.md @@ -134,10 +134,12 @@ export interface IContainer extends IEventProvider, IFluidRout close(error?: ICriticalContainerError): void; closeAndGetPendingLocalState(): string; readonly closed: boolean; + connect?(): void; // @deprecated readonly connected: boolean; readonly connectionState: ConnectionState; deltaManager: IDeltaManager; + disconnect?(): void; // @alpha forceReadonly?(readonly: boolean): any; getAbsoluteUrl(relativeUrl: string): Promise; diff --git a/common/lib/container-definitions/src/loader.ts b/common/lib/container-definitions/src/loader.ts index 680943f220da..8ff25fd25479 100644 --- a/common/lib/container-definitions/src/loader.ts +++ b/common/lib/container-definitions/src/loader.ts @@ -252,17 +252,27 @@ export interface IContainer extends IEventProvider, IFluidRout /** * Boolean indicating whether the container is currently connected or not - * @deprecated - 0.58, This API will be removed in 0.60.0 + * @deprecated - 0.58, This API will be removed in 1.0 * Check `connectionState === ConnectionState.Connected` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ readonly connected: boolean; + /** + * Attempts to connect the container to the delta stream and process ops + */ + connect?(): void; + + /** + * Disconnects the container from the delta stream and stops processing ops + */ + disconnect?(): void; + /** * Dictates whether or not the current container will automatically attempt to reconnect to the delta stream * after receiving a disconnect event * @param reconnect - Boolean indicating if reconnect should automatically occur - * @deprecated - 0.58, This API will be removed in 0.60.0 + * @deprecated - 0.58, This API will be removed in 1.0 * Use `connect()` and `disconnect()` instead of `setAutoReconnect(true)` and `setAutoReconnect(false)` respectively * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ @@ -270,7 +280,7 @@ export interface IContainer extends IEventProvider, IFluidRout /** * Have the container attempt to resume processing ops - * @deprecated - 0.58, This API will be removed in 0.60.0 + * @deprecated - 0.58, This API will be removed in 1.0 * Use `connect()` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ diff --git a/packages/framework/fluid-static/src/fluidContainer.ts b/packages/framework/fluid-static/src/fluidContainer.ts index 97b133b79253..71d83f77f5d9 100644 --- a/packages/framework/fluid-static/src/fluidContainer.ts +++ b/packages/framework/fluid-static/src/fluidContainer.ts @@ -74,7 +74,7 @@ export interface IFluidContainerEvents extends IEvent { export interface IFluidContainer extends IEventProvider { /** * Whether the container is connected to the collaboration session. - * @deprecated - 0.58, This API will be removed in 0.60.0 + * @deprecated - 0.58, This API will be removed in 1.0 * Check `connectionState === ConnectionState.Connected` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index 1b7b34259f33..0c823e23bf84 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -397,7 +397,6 @@ export class Container extends EventEmitterWithErrorHandling i private resumedOpProcessingAfterLoad = false; private firstConnection = true; - private manualReconnectInProgress = false; private readonly connectionTransitionTimes: number[] = []; private messageCountAfterDisconnection: number = 0; private _loadedFromVersion: IVersion | undefined; @@ -913,7 +912,7 @@ export class Container extends EventEmitterWithErrorHandling i * Dictates whether or not the current container will automatically attempt to reconnect to the delta stream * after receiving a disconnect event * @param reconnect - Boolean indicating if reconnect should automatically occur - * @deprecated - 0.58, This API will be removed in 0.60.0 + * @deprecated - 0.58, This API will be removed in 1.0 * Use `connect()` and `disconnect()` instead of `setAutoReconnect(true)` and `setAutoReconnect(false)` respectively * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ @@ -921,7 +920,19 @@ export class Container extends EventEmitterWithErrorHandling i if (this.closed) { throw new Error("Attempting to setAutoReconnect() a closed Container"); } + const mode = reconnect ? ReconnectMode.Enabled : ReconnectMode.Disabled; + this.setAutoReconnectInternal(mode); + + // If container state is not attached and resumed, then don't connect to delta stream. Also don't set the + // manual reconnection flag to true as we haven't made the initial connection yet. + if (reconnect && this._attachState === AttachState.Attached && this.resumedOpProcessingAfterLoad) { + // Ensure connection to web socket + this.connectToDeltaStream({ reason: "autoReconnect" }); + } + } + + private setAutoReconnectInternal(mode: ReconnectMode) { const currentMode = this._deltaManager.connectionManager.reconnectMode; if (currentMode === mode) { @@ -933,29 +944,23 @@ export class Container extends EventEmitterWithErrorHandling i this.setAutoReconnectTime = now; this.mc.logger.sendTelemetryEvent({ - eventName: reconnect ? "AutoReconnectEnabled" : "AutoReconnectDisabled", + eventName: mode === ReconnectMode.Enabled ? "AutoReconnectEnabled" : "AutoReconnectDisabled", connectionMode: this.connectionMode, connectionState: ConnectionState[this.connectionState], duration, }); this._deltaManager.connectionManager.setAutoReconnect(mode); - - // If container state is not attached and resumed, then don't connect to delta stream. Also don't set the - // manual reconnection flag to true as we haven't made the initial connection yet. - if (reconnect && this._attachState === AttachState.Attached && this.resumedOpProcessingAfterLoad) { - if (this.connectionState === ConnectionState.Disconnected) { - // Only track this as a manual reconnection if we are truly the ones kicking it off. - this.manualReconnectInProgress = true; - } - - // Ensure connection to web socket - this.connectToDeltaStream({ reason: "autoReconnect" }); - } } public connect() { - if (!this.closed && !this.connected) { + if (this.closed) { + throw new UsageError(`The Container is closed and cannot be connected`); + } + else if (this._attachState !== AttachState.Attached) { + throw new UsageError(`The Container is not attached and cannot be connected`); + } + else if (!this.connected) { // Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler(). // If there is gap, we will learn about it once connected, but the gap should be small (if any), // assuming that connect() is called quickly after initial container boot. @@ -967,38 +972,19 @@ export class Container extends EventEmitterWithErrorHandling i assert(!this.closed, "Attempting to connect() a closed Container"); assert(this._attachState === AttachState.Attached, "Attempting to connect() a container that is not attached"); - // Resume processing ops - if (!this.resumedOpProcessingAfterLoad) { - this.resumedOpProcessingAfterLoad = true; - this._deltaManager.inbound.resume(); - this._deltaManager.inboundSignal.resume(); - } - - // Ensure connection to web socket - this.connectToDeltaStream(args); - - const mode = ReconnectMode.Enabled; - const currentMode = this._deltaManager.connectionManager.reconnectMode; + // Resume processing ops and connect to delta stream + this.resumeInternal(args); // Set Auto Reconnect Mode - if (currentMode !== mode) { - const now = performance.now(); - const duration = now - this.setAutoReconnectTime; - this.setAutoReconnectTime = now; - - this.mc.logger.sendTelemetryEvent({ - eventName: "AutoReconnectEnabled", - connectionMode: this.connectionMode, - connectionState: ConnectionState[this.connectionState], - duration, - }); - - this._deltaManager.connectionManager.setAutoReconnect(mode); - } + const mode = ReconnectMode.Enabled; + this.setAutoReconnectInternal(mode); } public disconnect() { - if (!this.closed) { + if (this.closed) { + throw new UsageError(`The Container is closed and cannot be disconnected`); + } + else { this.disconnectInternal(); } } @@ -1006,30 +992,14 @@ export class Container extends EventEmitterWithErrorHandling i private disconnectInternal() { assert(!this.closed, "Attempting to disconnect() a closed Container"); - const mode = ReconnectMode.Disabled; - const currentMode = this._deltaManager.connectionManager.reconnectMode; - // Set Auto Reconnect Mode - if (currentMode !== mode) { - const now = performance.now(); - const duration = now - this.setAutoReconnectTime; - this.setAutoReconnectTime = now; - - this.mc.logger.sendTelemetryEvent({ - eventName: "AutoReconnectDisabled", - connectionMode: this.connectionMode, - connectionState: ConnectionState[this.connectionState], - duration, - }); - - // ConnectionManager will handle disconnecting the container - this._deltaManager.connectionManager.setAutoReconnect(mode); - } + const mode = ReconnectMode.Disabled; + this.setAutoReconnectInternal(mode); } /** * Have the container attempt to resume processing ops - * @deprecated - 0.58, This API will be removed in 0.60.0 + * @deprecated - 0.58, This API will be removed in 1.0 * Use `connect()` instead * See https://github.com/microsoft/FluidFramework/issues/9167 for context */ @@ -1578,7 +1548,6 @@ export class Container extends EventEmitterWithErrorHandling i }); deltaManager.on("disconnect", (reason: string) => { - this.manualReconnectInProgress = false; this.collabWindowTracker.stopSequenceNumberUpdate(); this.connectionStateHandler.receivedDisconnectEvent(reason); }); @@ -1645,8 +1614,6 @@ export class Container extends EventEmitterWithErrorHandling i } if (this.firstConnection) { connectionInitiationReason = "InitialConnect"; - } else if (this.manualReconnectInProgress) { - connectionInitiationReason = "ManualReconnect"; } else { connectionInitiationReason = "AutoReconnect"; } @@ -1671,7 +1638,6 @@ export class Container extends EventEmitterWithErrorHandling i if (value === ConnectionState.Connected) { this.firstConnection = false; - this.manualReconnectInProgress = false; } } From 05271fb79814079af07044c98ed31688acbcfb85 Mon Sep 17 00:00:00 2001 From: scottn12 Date: Wed, 6 Apr 2022 12:57:31 -0700 Subject: [PATCH 14/14] change connect reason to DocumentConnect --- packages/loader/container-loader/src/container.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/loader/container-loader/src/container.ts b/packages/loader/container-loader/src/container.ts index 0c823e23bf84..c41d50c489e2 100644 --- a/packages/loader/container-loader/src/container.ts +++ b/packages/loader/container-loader/src/container.ts @@ -964,7 +964,7 @@ export class Container extends EventEmitterWithErrorHandling i // Note: no need to fetch ops as we do it preemptively as part of DeltaManager.attachOpHandler(). // If there is gap, we will learn about it once connected, but the gap should be small (if any), // assuming that connect() is called quickly after initial container boot. - this.connectInternal({ reason: "DocumentOpenResume", fetchOpsFromStorage: false }); + this.connectInternal({ reason: "DocumentConnect", fetchOpsFromStorage: false }); } }