@fluidframework/container-loader 2.0.0-dev.4.4.0.162574 → 2.0.0-dev.5.3.2.178189
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.
- package/CHANGELOG.md +59 -0
- package/README.md +27 -3
- package/dist/catchUpMonitor.d.ts +1 -1
- package/dist/catchUpMonitor.d.ts.map +1 -1
- package/dist/catchUpMonitor.js.map +1 -1
- package/dist/connectionManager.d.ts +3 -2
- package/dist/connectionManager.d.ts.map +1 -1
- package/dist/connectionManager.js +32 -13
- package/dist/connectionManager.js.map +1 -1
- package/dist/connectionStateHandler.d.ts +18 -3
- package/dist/connectionStateHandler.d.ts.map +1 -1
- package/dist/connectionStateHandler.js +34 -9
- package/dist/connectionStateHandler.js.map +1 -1
- package/dist/container.d.ts +99 -70
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +260 -218
- package/dist/container.js.map +1 -1
- package/dist/containerContext.d.ts +24 -67
- package/dist/containerContext.d.ts.map +1 -1
- package/dist/containerContext.js +28 -217
- package/dist/containerContext.js.map +1 -1
- package/dist/containerStorageAdapter.d.ts +3 -3
- package/dist/containerStorageAdapter.d.ts.map +1 -1
- package/dist/containerStorageAdapter.js +29 -6
- package/dist/containerStorageAdapter.js.map +1 -1
- package/dist/contracts.d.ts +9 -3
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/deltaManager.d.ts +22 -9
- package/dist/deltaManager.d.ts.map +1 -1
- package/dist/deltaManager.js +42 -31
- package/dist/deltaManager.js.map +1 -1
- package/dist/deltaQueue.d.ts +2 -3
- package/dist/deltaQueue.d.ts.map +1 -1
- package/dist/deltaQueue.js +2 -3
- package/dist/deltaQueue.js.map +1 -1
- package/dist/disposal.d.ts +13 -0
- package/dist/disposal.d.ts.map +1 -0
- package/dist/disposal.js +25 -0
- package/dist/disposal.js.map +1 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +9 -8
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +47 -61
- package/dist/loader.js.map +1 -1
- package/dist/noopHeuristic.d.ts +23 -0
- package/dist/noopHeuristic.d.ts.map +1 -0
- package/dist/{collabWindowTracker.js → noopHeuristic.js} +30 -42
- package/dist/noopHeuristic.js.map +1 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/protocol.d.ts +7 -12
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +17 -19
- package/dist/protocol.js.map +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts +1 -1
- package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/dist/protocolTreeDocumentStorageService.js.map +1 -1
- package/dist/quorum.d.ts +1 -17
- package/dist/quorum.d.ts.map +1 -1
- package/dist/quorum.js +1 -17
- package/dist/quorum.js.map +1 -1
- package/dist/retriableDocumentStorageService.d.ts +3 -2
- package/dist/retriableDocumentStorageService.d.ts.map +1 -1
- package/dist/retriableDocumentStorageService.js.map +1 -1
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +8 -1
- package/dist/utils.js.map +1 -1
- package/lib/catchUpMonitor.d.ts +1 -1
- package/lib/catchUpMonitor.d.ts.map +1 -1
- package/lib/catchUpMonitor.js.map +1 -1
- package/lib/connectionManager.d.ts +3 -2
- package/lib/connectionManager.d.ts.map +1 -1
- package/lib/connectionManager.js +33 -14
- package/lib/connectionManager.js.map +1 -1
- package/lib/connectionStateHandler.d.ts +18 -3
- package/lib/connectionStateHandler.d.ts.map +1 -1
- package/lib/connectionStateHandler.js +35 -10
- package/lib/connectionStateHandler.js.map +1 -1
- package/lib/container.d.ts +99 -70
- package/lib/container.d.ts.map +1 -1
- package/lib/container.js +264 -222
- package/lib/container.js.map +1 -1
- package/lib/containerContext.d.ts +24 -67
- package/lib/containerContext.d.ts.map +1 -1
- package/lib/containerContext.js +28 -217
- package/lib/containerContext.js.map +1 -1
- package/lib/containerStorageAdapter.d.ts +3 -3
- package/lib/containerStorageAdapter.d.ts.map +1 -1
- package/lib/containerStorageAdapter.js +29 -6
- package/lib/containerStorageAdapter.js.map +1 -1
- package/lib/contracts.d.ts +9 -3
- package/lib/contracts.d.ts.map +1 -1
- package/lib/contracts.js.map +1 -1
- package/lib/deltaManager.d.ts +22 -9
- package/lib/deltaManager.d.ts.map +1 -1
- package/lib/deltaManager.js +44 -33
- package/lib/deltaManager.js.map +1 -1
- package/lib/deltaQueue.d.ts +2 -3
- package/lib/deltaQueue.d.ts.map +1 -1
- package/lib/deltaQueue.js +2 -3
- package/lib/deltaQueue.js.map +1 -1
- package/lib/disposal.d.ts +13 -0
- package/lib/disposal.d.ts.map +1 -0
- package/lib/disposal.js +21 -0
- package/lib/disposal.js.map +1 -0
- package/lib/index.d.ts +1 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/loader.d.ts +9 -8
- package/lib/loader.d.ts.map +1 -1
- package/lib/loader.js +47 -61
- package/lib/loader.js.map +1 -1
- package/lib/noopHeuristic.d.ts +23 -0
- package/lib/noopHeuristic.d.ts.map +1 -0
- package/lib/{collabWindowTracker.js → noopHeuristic.js} +30 -42
- package/lib/noopHeuristic.js.map +1 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/protocol.d.ts +7 -12
- package/lib/protocol.d.ts.map +1 -1
- package/lib/protocol.js +15 -18
- package/lib/protocol.js.map +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts +1 -1
- package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
- package/lib/protocolTreeDocumentStorageService.js.map +1 -1
- package/lib/quorum.d.ts +1 -17
- package/lib/quorum.d.ts.map +1 -1
- package/lib/quorum.js +1 -16
- package/lib/quorum.js.map +1 -1
- package/lib/retriableDocumentStorageService.d.ts +3 -2
- package/lib/retriableDocumentStorageService.d.ts.map +1 -1
- package/lib/retriableDocumentStorageService.js.map +1 -1
- package/lib/utils.d.ts +2 -0
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +7 -1
- package/lib/utils.js.map +1 -1
- package/package.json +22 -20
- package/src/catchUpMonitor.ts +1 -1
- package/src/connectionManager.ts +40 -22
- package/src/connectionStateHandler.ts +66 -17
- package/src/container.ts +464 -292
- package/src/containerContext.ts +33 -341
- package/src/containerStorageAdapter.ts +40 -10
- package/src/contracts.ts +11 -3
- package/src/deltaManager.ts +74 -45
- package/src/deltaQueue.ts +2 -3
- package/src/disposal.ts +25 -0
- package/src/index.ts +1 -8
- package/src/loader.ts +85 -83
- package/src/{collabWindowTracker.ts → noopHeuristic.ts} +37 -47
- package/src/packageVersion.ts +1 -1
- package/src/protocol.ts +18 -39
- package/src/protocolTreeDocumentStorageService.ts +1 -1
- package/src/quorum.ts +2 -31
- package/src/retriableDocumentStorageService.ts +4 -2
- package/src/utils.ts +15 -1
- package/dist/collabWindowTracker.d.ts +0 -19
- package/dist/collabWindowTracker.d.ts.map +0 -1
- package/dist/collabWindowTracker.js.map +0 -1
- package/dist/deltaManagerProxy.d.ts +0 -42
- package/dist/deltaManagerProxy.d.ts.map +0 -1
- package/dist/deltaManagerProxy.js +0 -79
- package/dist/deltaManagerProxy.js.map +0 -1
- package/lib/collabWindowTracker.d.ts +0 -19
- package/lib/collabWindowTracker.d.ts.map +0 -1
- package/lib/collabWindowTracker.js.map +0 -1
- package/lib/deltaManagerProxy.d.ts +0 -42
- package/lib/deltaManagerProxy.d.ts.map +0 -1
- package/lib/deltaManagerProxy.js +0 -74
- package/lib/deltaManagerProxy.js.map +0 -1
- package/src/deltaManagerProxy.ts +0 -109
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
# @fluidframework/container-loader
|
|
2
2
|
|
|
3
|
+
## 2.0.0-internal.5.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Move closeAndGetPendingLocalState to IContainerExperimental ([#16302](https://github.com/microsoft/FluidFramework/issues/16302)) [93151af787](https://github.com/microsoft/FluidFramework/commits/93151af787b76e547cf3460df47f81832131db8c)
|
|
8
|
+
|
|
9
|
+
This change deprecates the experimental method closeAndGetPendingLocalState on IContainer and moves it to IContainerExperimental.
|
|
10
|
+
IContainerExperimental is an interface that is easily casted to, which enables partners to access experimental features for testing and evaluation.
|
|
11
|
+
Moving the experimental method off IContainer will reduce exposure and churn on that production interface as we iterate on and finalize our experimental features.
|
|
12
|
+
Experimental features should not be used in production environments.
|
|
13
|
+
|
|
14
|
+
## 2.0.0-internal.5.2.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- IContainerContext members deprecated ([#16180](https://github.com/microsoft/FluidFramework/issues/16180)) [bf6a26cfe6](https://github.com/microsoft/FluidFramework/commits/bf6a26cfe6ac58386f2c9af260603a15b03ba84f)
|
|
19
|
+
|
|
20
|
+
IContainerContext members disposed, dispose(), serviceConfiguration, and id have been deprecated and will be removed in an upcoming release.
|
|
21
|
+
|
|
22
|
+
disposed - The disposed state on the IContainerContext is not meaningful to the runtime.
|
|
23
|
+
|
|
24
|
+
dispose() - The runtime is not permitted to dispose the IContainerContext, this results in an inconsistent system state.
|
|
25
|
+
|
|
26
|
+
serviceConfiguration - This property is redundant, and is unused by the runtime. The same information can be found via `deltaManager.serviceConfiguration` on this object if it is necessary.
|
|
27
|
+
|
|
28
|
+
id - The docId is already logged by the IContainerContext.taggedLogger for telemetry purposes, so this is generally unnecessary for telemetry. If the id is needed for other purposes it should be passed to the consumer explicitly.
|
|
29
|
+
|
|
30
|
+
## 2.0.0-internal.5.1.0
|
|
31
|
+
|
|
32
|
+
Dependency updates only.
|
|
33
|
+
|
|
34
|
+
## 2.0.0-internal.5.0.0
|
|
35
|
+
|
|
36
|
+
### Major Changes
|
|
37
|
+
|
|
38
|
+
- IContainer.dispose is now required [96484ac6c2](https://github.com/microsoft/FluidFramework/commits/96484ac6c24fed60f79d717616cb9072ab476488)
|
|
39
|
+
|
|
40
|
+
`IContainer.dispose` is now a required method. This method should dispose any resources and switch the container to a
|
|
41
|
+
permanently disconnected state.
|
|
42
|
+
|
|
43
|
+
See the
|
|
44
|
+
[Closure](https://github.com/microsoft/FluidFramework/blob/main/packages/loader/container-loader/README.md#closure)
|
|
45
|
+
section of Loader README.md for more details.
|
|
46
|
+
|
|
47
|
+
- Calling `IContainer.close(...)` will no longer dispose the container runtime, document service, or document storage service. [8b242fdc79](https://github.com/microsoft/FluidFramework/commits/8b242fdc796714cf1da9ad3f90d02efb122af0c2)
|
|
48
|
+
|
|
49
|
+
If the container is not expected to be used after the `close(...)` call, replace it instead with a
|
|
50
|
+
`IContainer.dispose(...)` call (this should be the most common case). Using `IContainer.dispose(...)` will no longer
|
|
51
|
+
switch the container to "readonly" mode and relevant code should instead listen to the Container's "disposed" event.
|
|
52
|
+
|
|
53
|
+
If you intend to pass your own critical error to the container, use `IContainer.close(...)`. Once you are done using the
|
|
54
|
+
container, call `IContainer.dispose(...)`.
|
|
55
|
+
|
|
56
|
+
See the [Closure](packages/loader/container-loader/README.md#Closure) section of Loader README.md for more details.
|
|
57
|
+
|
|
58
|
+
## 2.0.0-internal.4.4.0
|
|
59
|
+
|
|
60
|
+
Dependency updates only.
|
|
61
|
+
|
|
3
62
|
## 2.0.0-internal.4.1.0
|
|
4
63
|
|
|
5
64
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -66,6 +66,7 @@ Please see specific sections for more details on these states and events - this
|
|
|
66
66
|
2. ["closed"](#Closure) event: If raised with error, host is responsible for conveying error in some form to the user. Container is left in disconnected & readonly state when it is closed (because of error or not).
|
|
67
67
|
3. ["readonly"](#Readonly-states) event: Host should have some indication to user that container is not editable. User permissions can change over lifetime of Container, but they can't change per connection session (in other words, change in permissions causes disconnect and reconnect). Hosts are advised to recheck this property on every reconnect.
|
|
68
68
|
4. [Dirty events](#Dirty-events): Host should have some reasonable UX / workflows to ensure user does not lose edits unexpectedly. I.e. there is enough signals (potentially including blocking user from closing container) ensuring that all user edits make it to storage, unless user explicitly choses to lose such edits.
|
|
69
|
+
5. [Closing or disposing containers](#containerclose): For most cases, you should use the `IContainer.dispose(...)` API to free up resources. If you intend on using the container after closure, or need to pass some critical error to the container, use the `IContainer.close(...)` API.
|
|
69
70
|
|
|
70
71
|
## Expectations from container runtime and data store implementers
|
|
71
72
|
|
|
@@ -89,7 +90,7 @@ Usually container is returned when state of container (and data stores) is rehyd
|
|
|
89
90
|
|
|
90
91
|
### Closure
|
|
91
92
|
|
|
92
|
-
Container can be closed directly by host by calling `Container.close()` and/or `Container.dispose()`. If the container is expected to be used upon closure, use the `close()` API. Otherwise, use the `dispose()` API. The differences between these methods are detailed in the sections below.
|
|
93
|
+
Container can be closed directly by host by calling `Container.close()` and/or `Container.dispose()`. If the container is expected to be used upon closure, or you need to pass your own critical error to the container, use the `close()` API. Otherwise, use the `dispose()` API. The differences between these methods are detailed in the sections below.
|
|
93
94
|
|
|
94
95
|
#### `Container.close()`
|
|
95
96
|
|
|
@@ -97,7 +98,9 @@ Once closed, container terminates connection to ordering service, and any local
|
|
|
97
98
|
|
|
98
99
|
The "closed" state effectively means the container is disconnected forever and cannot be reconnected.
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
If after some time a closed container is no longer needed, calling `Container.dispose()` will dispose the runtime resources.
|
|
102
|
+
|
|
103
|
+
Container can also be closed and/or disposed by runtime itself as result of some critical error. Critical errors can be internal (like violation in op ordering invariants), or external (file was deleted). Please see [Error Handling](#Error-handling) for more details.
|
|
101
104
|
|
|
102
105
|
When container is closed, the following is true (in no particular order):
|
|
103
106
|
|
|
@@ -106,7 +109,7 @@ When container is closed, the following is true (in no particular order):
|
|
|
106
109
|
3. "readonly" event fires on DeltaManager & Container (and Container.readonly property is set to true) indicating to all data stores that container is read-only, and data stores should not allow local edits, as they are not going to make it.
|
|
107
110
|
4. "disconnected" event fires, if connection was active at the moment of container closure.
|
|
108
111
|
|
|
109
|
-
`"closed"` event is available on Container for hosts.
|
|
112
|
+
`"closed"` event is available on Container for hosts.
|
|
110
113
|
|
|
111
114
|
#### `Container.dispose()`
|
|
112
115
|
|
|
@@ -196,6 +199,27 @@ Please note that hosts can implement various strategies on how to handle disconn
|
|
|
196
199
|
|
|
197
200
|
It's worth pointing out that being connected does not mean all user edits are preserved on container closure. There is latency in the system, and loader layer does not provide any guarantees here. Not every implementation needs a solution here (games likely do not care), and thus solving this problem is pushed to framework level (i.e. having a data store that can expose `'dirtyDocument'` signal from ContainerRuntime and request route that can return such data store).
|
|
198
201
|
|
|
202
|
+
## Connection State Transitions Flow Chart
|
|
203
|
+
|
|
204
|
+
```mermaid
|
|
205
|
+
flowchart TD;
|
|
206
|
+
A(Disconnected)-->B{Reconnect on error if \n AutoReconnect Enabled?};
|
|
207
|
+
B--Yes-->C(Establishing Connection);
|
|
208
|
+
B--No-->D[Connection during Container \n connect call];
|
|
209
|
+
D-->C
|
|
210
|
+
C-->E{Connection Success \n including any Retry?};
|
|
211
|
+
E--No-->F[Error or container.close or container.disconnect];
|
|
212
|
+
A-->F;
|
|
213
|
+
F-->A;
|
|
214
|
+
E--Yes-->G(Catching Up);
|
|
215
|
+
G-->F;
|
|
216
|
+
G-->H{Which Connection Mode?};
|
|
217
|
+
H--Read-->I(Connected);
|
|
218
|
+
H--Write-->J[Wait for Join Op];
|
|
219
|
+
J-->I;
|
|
220
|
+
I-->F;
|
|
221
|
+
```
|
|
222
|
+
|
|
199
223
|
## Readonly states
|
|
200
224
|
|
|
201
225
|
User permissions can change over lifetime of Container. They can't change during single connection session (in other words, change in permissions causes disconnect and reconnect). Hosts are advised to recheck this property on every reconnect.
|
package/dist/catchUpMonitor.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import { IDisposable } from "@fluidframework/
|
|
5
|
+
import { IDisposable } from "@fluidframework/core-interfaces";
|
|
6
6
|
import { IDeltaManager } from "@fluidframework/container-definitions";
|
|
7
7
|
/** @see CatchUpMonitor for usage */
|
|
8
8
|
declare type CaughtUpListener = () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catchUpMonitor.d.ts","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"catchUpMonitor.d.ts","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAC;AAGtE,oCAAoC;AACpC,aAAK,gBAAgB,GAAG,MAAM,IAAI,CAAC;AAEnC,mGAAmG;AACnG,oBAAY,eAAe,GAAG,WAAW,CAAC;AAE1C;;;GAGG;AACH,qBAAa,cAAe,YAAW,eAAe;IAepD,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAf1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAkB;IAElC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAKxB;IAEF;;OAEG;gBAEe,YAAY,EAAE,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EACrC,QAAQ,EAAE,gBAAgB;IAerC,QAAQ,EAAE,OAAO,CAAS;IAC1B,OAAO;CAQd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catchUpMonitor.js","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,+DAAsD;AAUtD;;;GAGG;AACH,MAAa,cAAc;IAW1B;;OAEG;IACH,YACkB,YAAqC,EACrC,QAA0B;QAD1B,iBAAY,GAAZ,YAAY,CAAyB;QACrC,aAAQ,GAAR,QAAQ,CAAkB;QAdpC,aAAQ,GAAY,KAAK,CAAC;QAEjB,cAAS,GAAG,CAAC,OAA0D,EAAE,EAAE;YAC3F,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,eAAe,EAAE;gBACrE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;aAChB;QACF,CAAC,CAAC;QAsBK,aAAQ,GAAY,KAAK,CAAC;QAbhC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC;QAE5D,IAAA,qBAAM,EACL,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAC5D,KAAK,CAAC,oEAAoE,CAC1E,CAAC;QAEF,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE3C,wEAAwE;QACxE,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC1E,CAAC;IAGM,OAAO;QACb,IAAI,IAAI,CAAC,QAAQ,EAAE;YAClB,OAAO;SACP;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC;CACD;AAxCD,wCAwCC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDisposable } from \"@fluidframework/
|
|
1
|
+
{"version":3,"file":"catchUpMonitor.js","sourceRoot":"","sources":["../src/catchUpMonitor.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,+DAAsD;AAUtD;;;GAGG;AACH,MAAa,cAAc;IAW1B;;OAEG;IACH,YACkB,YAAqC,EACrC,QAA0B;QAD1B,iBAAY,GAAZ,YAAY,CAAyB;QACrC,aAAQ,GAAR,QAAQ,CAAkB;QAdpC,aAAQ,GAAY,KAAK,CAAC;QAEjB,cAAS,GAAG,CAAC,OAA0D,EAAE,EAAE;YAC3F,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,eAAe,EAAE;gBACrE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;aAChB;QACF,CAAC,CAAC;QAsBK,aAAQ,GAAY,KAAK,CAAC;QAbhC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,kBAAkB,CAAC;QAE5D,IAAA,qBAAM,EACL,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAC5D,KAAK,CAAC,oEAAoE,CAC1E,CAAC;QAEF,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE3C,wEAAwE;QACxE,IAAI,CAAC,SAAS,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC1E,CAAC;IAGM,OAAO;QACb,IAAI,IAAI,CAAC,QAAQ,EAAE;YAClB,OAAO;SACP;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC;CACD;AAxCD,wCAwCC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IDisposable } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IDeltaManager } from \"@fluidframework/container-definitions\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\n\n/** @see CatchUpMonitor for usage */\ntype CaughtUpListener = () => void;\n\n/** Monitor that emits an event when a Container has caught up to a given point in the op stream */\nexport type ICatchUpMonitor = IDisposable;\n\n/**\n * Monitors a Container's DeltaManager, notifying listeners when all ops have been processed\n * that were known at the time the monitor was created.\n */\nexport class CatchUpMonitor implements ICatchUpMonitor {\n\tprivate readonly targetSeqNumber: number;\n\tprivate caughtUp: boolean = false;\n\n\tprivate readonly opHandler = (message: Pick<ISequencedDocumentMessage, \"sequenceNumber\">) => {\n\t\tif (!this.caughtUp && message.sequenceNumber >= this.targetSeqNumber) {\n\t\t\tthis.caughtUp = true;\n\t\t\tthis.listener();\n\t\t}\n\t};\n\n\t/**\n\t * Create the CatchUpMonitor, setting the target sequence number to wait for based on DeltaManager's current state.\n\t */\n\tconstructor(\n\t\tprivate readonly deltaManager: IDeltaManager<any, any>,\n\t\tprivate readonly listener: CaughtUpListener,\n\t) {\n\t\tthis.targetSeqNumber = this.deltaManager.lastKnownSeqNumber;\n\n\t\tassert(\n\t\t\tthis.targetSeqNumber >= this.deltaManager.lastSequenceNumber,\n\t\t\t0x37c /* Cannot wait for seqNumber below last processed sequence number */,\n\t\t);\n\n\t\tthis.deltaManager.on(\"op\", this.opHandler);\n\n\t\t// Simulate the last processed op to set caughtUp in case we already are\n\t\tthis.opHandler({ sequenceNumber: this.deltaManager.lastSequenceNumber });\n\t}\n\n\tpublic disposed: boolean = false;\n\tpublic dispose() {\n\t\tif (this.disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.disposed = true;\n\n\t\tthis.deltaManager.off(\"op\", this.opHandler);\n\t}\n}\n"]}
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { ITelemetryProperties } from "@fluidframework/core-interfaces";
|
|
6
6
|
import { IDeltaQueue, ReadOnlyInfo, ICriticalContainerError } from "@fluidframework/container-definitions";
|
|
7
7
|
import { IDocumentService } from "@fluidframework/driver-definitions";
|
|
8
8
|
import { ConnectionMode, IClient, IClientConfiguration, IClientDetails, IDocumentMessage, ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
9
|
+
import { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils";
|
|
9
10
|
import { ReconnectMode, IConnectionManager, IConnectionManagerFactoryArgs } from "./contracts";
|
|
10
11
|
/**
|
|
11
12
|
* Implementation of IConnectionManager, used by Container class
|
|
@@ -84,7 +85,7 @@ export declare class ConnectionManager implements IConnectionManager {
|
|
|
84
85
|
private get readonly();
|
|
85
86
|
get readOnlyInfo(): ReadOnlyInfo;
|
|
86
87
|
private static detailsFromConnection;
|
|
87
|
-
constructor(serviceProvider: () => IDocumentService | undefined, containerDirty: () => boolean, client: IClient, reconnectAllowed: boolean, logger:
|
|
88
|
+
constructor(serviceProvider: () => IDocumentService | undefined, containerDirty: () => boolean, client: IClient, reconnectAllowed: boolean, logger: ITelemetryLoggerExt, props: IConnectionManagerFactoryArgs);
|
|
88
89
|
dispose(error?: ICriticalContainerError, switchToReadonly?: boolean): void;
|
|
89
90
|
/**
|
|
90
91
|
* Enables or disables automatic reconnecting.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectionManager.d.ts","sourceRoot":"","sources":["../src/connectionManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"connectionManager.d.ts","sourceRoot":"","sources":["../src/connectionManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,13 +11,13 @@ exports.ConnectionManager = void 0;
|
|
|
11
11
|
const abort_controller_1 = __importDefault(require("abort-controller"));
|
|
12
12
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
13
13
|
const container_utils_1 = require("@fluidframework/container-utils");
|
|
14
|
-
const driver_definitions_1 = require("@fluidframework/driver-definitions");
|
|
15
14
|
const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
16
15
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
17
16
|
const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
|
|
18
17
|
const contracts_1 = require("./contracts");
|
|
19
18
|
const deltaQueue_1 = require("./deltaQueue");
|
|
20
19
|
const protocol_1 = require("./protocol");
|
|
20
|
+
const utils_1 = require("./utils");
|
|
21
21
|
const MaxReconnectDelayInMs = 8000;
|
|
22
22
|
const InitialReconnectDelayInMs = 1000;
|
|
23
23
|
const DefaultChunkSize = 16 * 1024;
|
|
@@ -41,8 +41,9 @@ const clientNoDeltaStream = {
|
|
|
41
41
|
};
|
|
42
42
|
const clientIdNoDeltaStream = "storage-only client";
|
|
43
43
|
class NoDeltaStream extends common_utils_1.TypedEventEmitter {
|
|
44
|
-
constructor() {
|
|
45
|
-
super(
|
|
44
|
+
constructor(storageOnlyReason) {
|
|
45
|
+
super();
|
|
46
|
+
this.storageOnlyReason = storageOnlyReason;
|
|
46
47
|
this.clientId = clientIdNoDeltaStream;
|
|
47
48
|
this.claims = {
|
|
48
49
|
scopes: [protocol_definitions_1.ScopeType.DocRead],
|
|
@@ -84,6 +85,9 @@ class NoDeltaStream extends common_utils_1.TypedEventEmitter {
|
|
|
84
85
|
this._disposed = true;
|
|
85
86
|
}
|
|
86
87
|
}
|
|
88
|
+
function isNoDeltaStreamConnection(connection) {
|
|
89
|
+
return connection instanceof NoDeltaStream;
|
|
90
|
+
}
|
|
87
91
|
const waitForOnline = async () => {
|
|
88
92
|
var _a;
|
|
89
93
|
// Only wait if we have a strong signal that we're offline - otherwise assume we're online.
|
|
@@ -249,13 +253,19 @@ class ConnectionManager {
|
|
|
249
253
|
return this.readOnlyInfo.readonly;
|
|
250
254
|
}
|
|
251
255
|
get readOnlyInfo() {
|
|
252
|
-
|
|
256
|
+
let storageOnly = false;
|
|
257
|
+
let storageOnlyReason;
|
|
258
|
+
if (isNoDeltaStreamConnection(this.connection)) {
|
|
259
|
+
storageOnly = true;
|
|
260
|
+
storageOnlyReason = this.connection.storageOnlyReason;
|
|
261
|
+
}
|
|
253
262
|
if (storageOnly || this._forceReadonly || this._readonlyPermissions === true) {
|
|
254
263
|
return {
|
|
255
264
|
readonly: true,
|
|
256
265
|
forced: this._forceReadonly,
|
|
257
266
|
permissions: this._readonlyPermissions,
|
|
258
267
|
storageOnly,
|
|
268
|
+
storageOnlyReason,
|
|
259
269
|
};
|
|
260
270
|
}
|
|
261
271
|
return { readonly: this._readonlyPermissions };
|
|
@@ -279,7 +289,6 @@ class ConnectionManager {
|
|
|
279
289
|
return;
|
|
280
290
|
}
|
|
281
291
|
this._disposed = true;
|
|
282
|
-
this.pendingConnection = undefined;
|
|
283
292
|
// Ensure that things like triggerConnect() will short circuit
|
|
284
293
|
this._reconnectMode = contracts_1.ReconnectMode.Never;
|
|
285
294
|
this._outbound.clear();
|
|
@@ -376,7 +385,7 @@ class ConnectionManager {
|
|
|
376
385
|
let pendingConnectionMode;
|
|
377
386
|
if (this.pendingConnection !== undefined) {
|
|
378
387
|
pendingConnectionMode = this.pendingConnection.connectionMode;
|
|
379
|
-
this.cancelConnection(); // Throw out in-progress connection attempt in favor of new attempt
|
|
388
|
+
this.cancelConnection(reason); // Throw out in-progress connection attempt in favor of new attempt
|
|
380
389
|
(0, common_utils_1.assert)(this.pendingConnection === undefined, 0x344 /* this.pendingConnection should be undefined */);
|
|
381
390
|
}
|
|
382
391
|
// If there is no specified ConnectionMode, try the previous mode, if there is no previous mode use default
|
|
@@ -410,6 +419,7 @@ class ConnectionManager {
|
|
|
410
419
|
},
|
|
411
420
|
connectionMode: requestedMode,
|
|
412
421
|
};
|
|
422
|
+
this.props.establishConnectionHandler(reason);
|
|
413
423
|
// This loop will keep trying to connect until successful, with a delay between each iteration.
|
|
414
424
|
while (connection === undefined) {
|
|
415
425
|
if (this._disposed) {
|
|
@@ -435,10 +445,8 @@ class ConnectionManager {
|
|
|
435
445
|
}
|
|
436
446
|
}
|
|
437
447
|
catch (origError) {
|
|
438
|
-
if (
|
|
439
|
-
|
|
440
|
-
(origError === null || origError === void 0 ? void 0 : origError.errorType) === driver_definitions_1.DriverErrorType.deltaStreamConnectionForbidden) {
|
|
441
|
-
connection = new NoDeltaStream();
|
|
448
|
+
if ((0, utils_1.isDeltaStreamConnectionForbiddenError)(origError)) {
|
|
449
|
+
connection = new NoDeltaStream(origError.storageOnlyReason);
|
|
442
450
|
requestedMode = "read";
|
|
443
451
|
break;
|
|
444
452
|
}
|
|
@@ -456,6 +464,7 @@ class ConnectionManager {
|
|
|
456
464
|
duration: telemetry_utils_1.TelemetryLogger.formatTick(common_utils_1.performance.now() - connectStartTime),
|
|
457
465
|
}, origError);
|
|
458
466
|
lastError = origError;
|
|
467
|
+
const waitStartTime = common_utils_1.performance.now();
|
|
459
468
|
const retryDelayFromError = (0, driver_utils_1.getRetryDelayFromError)(origError);
|
|
460
469
|
if (retryDelayFromError !== undefined) {
|
|
461
470
|
// If the error told us to wait, then we wait.
|
|
@@ -476,6 +485,14 @@ class ConnectionManager {
|
|
|
476
485
|
// NOTE: This isn't strictly true for drivers that don't require network (e.g. local driver). Really this logic
|
|
477
486
|
// should probably live in the driver.
|
|
478
487
|
await waitForOnline();
|
|
488
|
+
this.logger.sendPerformanceEvent({
|
|
489
|
+
eventName: "WaitBetweenConnectionAttempts",
|
|
490
|
+
duration: common_utils_1.performance.now() - waitStartTime,
|
|
491
|
+
details: JSON.stringify({
|
|
492
|
+
retryDelayFromError,
|
|
493
|
+
delayMs,
|
|
494
|
+
}),
|
|
495
|
+
});
|
|
479
496
|
}
|
|
480
497
|
}
|
|
481
498
|
// If we retried more than once, log an event about how long it took (this will not log to error table)
|
|
@@ -526,7 +543,7 @@ class ConnectionManager {
|
|
|
526
543
|
this.pendingReconnect = false;
|
|
527
544
|
if (this.connection === undefined) {
|
|
528
545
|
if (this.pendingConnection !== undefined) {
|
|
529
|
-
this.cancelConnection();
|
|
546
|
+
this.cancelConnection(reason);
|
|
530
547
|
return true;
|
|
531
548
|
}
|
|
532
549
|
return false;
|
|
@@ -553,11 +570,12 @@ class ConnectionManager {
|
|
|
553
570
|
/**
|
|
554
571
|
* Cancel in-progress connection attempt.
|
|
555
572
|
*/
|
|
556
|
-
cancelConnection() {
|
|
573
|
+
cancelConnection(reason) {
|
|
557
574
|
(0, common_utils_1.assert)(this.pendingConnection !== undefined, 0x345 /* this.pendingConnection is undefined when trying to cancel */);
|
|
558
575
|
this.pendingConnection.abort();
|
|
559
576
|
this.pendingConnection = undefined;
|
|
560
577
|
this.logger.sendTelemetryEvent({ eventName: "ConnectionCancelReceived" });
|
|
578
|
+
this.props.cancelConnectionHandler(`Cancel Pending Connection due to ${reason}`);
|
|
561
579
|
}
|
|
562
580
|
/**
|
|
563
581
|
* Once we've successfully gotten a connection, we need to set up state, attach event listeners, and process
|
|
@@ -721,7 +739,7 @@ class ConnectionManager {
|
|
|
721
739
|
// should probably live in the driver.
|
|
722
740
|
await waitForOnline();
|
|
723
741
|
this.triggerConnect(error !== undefined
|
|
724
|
-
? "
|
|
742
|
+
? "Reconnecting due to Error"
|
|
725
743
|
: `Reconnecting due to: ${disconnectMessage}`, requestedMode);
|
|
726
744
|
}
|
|
727
745
|
prepareMessageToSend(message) {
|
|
@@ -733,6 +751,7 @@ class ConnectionManager {
|
|
|
733
751
|
forcedReadonly: this.readOnlyInfo.forced,
|
|
734
752
|
readonlyPermissions: this.readOnlyInfo.permissions,
|
|
735
753
|
storageOnly: this.readOnlyInfo.storageOnly,
|
|
754
|
+
storageOnlyReason: this.readOnlyInfo.storageOnlyReason,
|
|
736
755
|
});
|
|
737
756
|
this.props.closeHandler(error);
|
|
738
757
|
return undefined;
|