@fluidframework/agent-scheduler 2.23.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +1 -4
- package/CHANGELOG.md +63 -55
- package/api-report/agent-scheduler.legacy.alpha.api.md +1 -1
- package/dist/scheduler.d.ts +5 -5
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +15 -14
- package/dist/scheduler.js.map +1 -1
- package/dist/taskSubscription.d.ts.map +1 -1
- package/dist/taskSubscription.js.map +1 -1
- package/lib/scheduler.d.ts +5 -5
- package/lib/scheduler.d.ts.map +1 -1
- package/lib/scheduler.js +15 -14
- package/lib/scheduler.js.map +1 -1
- package/lib/taskSubscription.d.ts.map +1 -1
- package/lib/taskSubscription.js.map +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/package.json +14 -17
- package/src/scheduler.ts +45 -39
- package/src/taskSubscription.ts +2 -2
- package/prettier.config.cjs +0 -8
package/.eslintrc.cjs
CHANGED
|
@@ -4,10 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
|
-
extends: [
|
|
8
|
-
require.resolve("@fluidframework/eslint-config-fluid/minimal-deprecated"),
|
|
9
|
-
"prettier",
|
|
10
|
-
],
|
|
7
|
+
extends: [require.resolve("@fluidframework/eslint-config-fluid/recommended"), "prettier"],
|
|
11
8
|
parserOptions: {
|
|
12
9
|
project: ["./tsconfig.json", "./src/test/tsconfig.json"],
|
|
13
10
|
},
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @fluidframework/agent-scheduler
|
|
2
2
|
|
|
3
|
+
## 2.31.0
|
|
4
|
+
|
|
5
|
+
Dependency updates only.
|
|
6
|
+
|
|
7
|
+
## 2.30.0
|
|
8
|
+
|
|
9
|
+
Dependency updates only.
|
|
10
|
+
|
|
3
11
|
## 2.23.0
|
|
4
12
|
|
|
5
13
|
Dependency updates only.
|
|
@@ -56,9 +64,9 @@ Dependency updates only.
|
|
|
56
64
|
|
|
57
65
|
### Minor Changes
|
|
58
66
|
|
|
59
|
-
-
|
|
67
|
+
- Update to TypeScript 5.4 ([#21214](https://github.com/microsoft/FluidFramework/pull/21214)) [0e6256c722](https://github.com/microsoft/FluidFramework/commit/0e6256c722d8bf024f4325bf02547daeeb18bfa6)
|
|
60
68
|
|
|
61
|
-
|
|
69
|
+
Update package implementations to use TypeScript 5.4.5.
|
|
62
70
|
|
|
63
71
|
## 2.0.0-rc.4.0.0
|
|
64
72
|
|
|
@@ -68,24 +76,24 @@ Dependency updates only.
|
|
|
68
76
|
|
|
69
77
|
### Major Changes
|
|
70
78
|
|
|
71
|
-
-
|
|
79
|
+
- Packages now use package.json "exports" and require modern module resolution [97d68aa06b](https://github.com/microsoft/FluidFramework/commit/97d68aa06bd5c022ecb026655814aea222a062ae)
|
|
72
80
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
Fluid Framework packages have been updated to use the [package.json "exports"
|
|
82
|
+
field](https://nodejs.org/docs/latest-v18.x/api/packages.html#exports) to define explicit entry points for both
|
|
83
|
+
TypeScript types and implementation code.
|
|
76
84
|
|
|
77
|
-
|
|
85
|
+
This means that using Fluid Framework packages require the following TypeScript settings in tsconfig.json:
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
- `"moduleResolution": "Node16"` with `"module": "Node16"`
|
|
88
|
+
- `"moduleResolution": "Bundler"` with `"module": "ESNext"`
|
|
81
89
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
We recommend using Node16/Node16 unless absolutely necessary. That will produce transpiled JavaScript that is suitable
|
|
91
|
+
for use with modern versions of Node.js _and_ Bundlers.
|
|
92
|
+
[See the TypeScript documentation](https://www.typescriptlang.org/tsconfig#moduleResolution) for more information
|
|
93
|
+
regarding the module and moduleResolution options.
|
|
86
94
|
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
**Node10 moduleResolution is not supported; it does not support Fluid Framework's API structuring pattern that is used
|
|
96
|
+
to distinguish stable APIs from those that are in development.**
|
|
89
97
|
|
|
90
98
|
## 2.0.0-rc.2.0.0
|
|
91
99
|
|
|
@@ -119,25 +127,25 @@ Dependency updates only.
|
|
|
119
127
|
|
|
120
128
|
### Major Changes
|
|
121
129
|
|
|
122
|
-
-
|
|
130
|
+
- test-utils: provideEntryPoint is required [871b3493dd](https://github.com/microsoft/FluidFramework/commits/871b3493dd0d7ea3a89be64998ceb6cb9021a04e)
|
|
123
131
|
|
|
124
|
-
|
|
132
|
+
The optional `provideEntryPoint` method has become required on a number of constructors. A value will need to be provided to the following classes:
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
- `BaseContainerRuntimeFactory`
|
|
135
|
+
- `RuntimeFactory`
|
|
136
|
+
- `ContainerRuntime` (constructor and `loadRuntime`)
|
|
137
|
+
- `FluidDataStoreRuntime`
|
|
130
138
|
|
|
131
|
-
|
|
132
|
-
|
|
139
|
+
See [testContainerRuntimeFactoryWithDefaultDataStore.ts](https://github.com/microsoft/FluidFramework/tree/main/packages/test/test-utils/src/testContainerRuntimeFactoryWithDefaultDataStore.ts) for an example implemtation of `provideEntryPoint` for ContainerRuntime.
|
|
140
|
+
See [pureDataObjectFactory.ts](https://github.com/microsoft/FluidFramework/tree/main/packages/framework/aqueduct/src/data-object-factories/pureDataObjectFactory.ts#L83) for an example implementation of `provideEntryPoint` for DataStoreRuntime.
|
|
133
141
|
|
|
134
|
-
|
|
142
|
+
Subsequently, various `entryPoint` and `getEntryPoint()` endpoints have become required. Please see [containerRuntime.ts](https://github.com/microsoft/FluidFramework/tree/main/packages/runtime/container-runtime/src/containerRuntime.ts) for example implementations of these APIs.
|
|
135
143
|
|
|
136
|
-
|
|
144
|
+
For more details, see [Removing-IFluidRouter.md](https://github.com/microsoft/FluidFramework/blob/main/packages/common/core-interfaces/Removing-IFluidRouter.md)
|
|
137
145
|
|
|
138
|
-
-
|
|
146
|
+
- Minimum TypeScript version now 5.1.6 [871b3493dd](https://github.com/microsoft/FluidFramework/commits/871b3493dd0d7ea3a89be64998ceb6cb9021a04e)
|
|
139
147
|
|
|
140
|
-
|
|
148
|
+
The minimum supported TypeScript version for Fluid 2.0 clients is now 5.1.6.
|
|
141
149
|
|
|
142
150
|
## 2.0.0-internal.6.4.0
|
|
143
151
|
|
|
@@ -151,32 +159,32 @@ Dependency updates only.
|
|
|
151
159
|
|
|
152
160
|
### Minor Changes
|
|
153
161
|
|
|
154
|
-
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
162
|
+
- Remove use of @fluidframework/common-definitions ([#16638](https://github.com/microsoft/FluidFramework/issues/16638)) [a8c81509c9](https://github.com/microsoft/FluidFramework/commits/a8c81509c9bf09cfb2092ebcf7265205f9eb6dbf)
|
|
163
|
+
|
|
164
|
+
The **@fluidframework/common-definitions** package is being deprecated, so the following interfaces and types are now
|
|
165
|
+
imported from the **@fluidframework/core-interfaces** package:
|
|
166
|
+
|
|
167
|
+
- interface IDisposable
|
|
168
|
+
- interface IErrorEvent
|
|
169
|
+
- interface IErrorEvent
|
|
170
|
+
- interface IEvent
|
|
171
|
+
- interface IEventProvider
|
|
172
|
+
- interface ILoggingError
|
|
173
|
+
- interface ITaggedTelemetryPropertyType
|
|
174
|
+
- interface ITelemetryBaseEvent
|
|
175
|
+
- interface ITelemetryBaseLogger
|
|
176
|
+
- interface ITelemetryErrorEvent
|
|
177
|
+
- interface ITelemetryGenericEvent
|
|
178
|
+
- interface ITelemetryLogger
|
|
179
|
+
- interface ITelemetryPerformanceEvent
|
|
180
|
+
- interface ITelemetryProperties
|
|
181
|
+
- type ExtendEventProvider
|
|
182
|
+
- type IEventThisPlaceHolder
|
|
183
|
+
- type IEventTransformer
|
|
184
|
+
- type ReplaceIEventThisPlaceHolder
|
|
185
|
+
- type ReplaceIEventThisPlaceHolder
|
|
186
|
+
- type TelemetryEventCategory
|
|
187
|
+
- type TelemetryEventPropertyType
|
|
180
188
|
|
|
181
189
|
## 2.0.0-internal.6.1.0
|
|
182
190
|
|
|
@@ -186,9 +194,9 @@ Dependency updates only.
|
|
|
186
194
|
|
|
187
195
|
### Major Changes
|
|
188
196
|
|
|
189
|
-
-
|
|
197
|
+
- Upgraded typescript transpilation target to ES2020 [8abce8cdb4](https://github.com/microsoft/FluidFramework/commits/8abce8cdb4e2832fb6405fb44e393bef03d5648a)
|
|
190
198
|
|
|
191
|
-
|
|
199
|
+
Upgraded typescript transpilation target to ES2020. This is done in order to decrease the bundle sizes of Fluid Framework packages. This has provided size improvements across the board for ex. Loader, Driver, Runtime etc. Reduced bundle sizes helps to load lesser code in apps and hence also helps to improve the perf.If any app wants to target any older versions of browsers with which this target version is not compatible, then they can use packages like babel to transpile to a older target.
|
|
192
200
|
|
|
193
201
|
## 2.0.0-internal.5.4.0
|
|
194
202
|
|
|
@@ -9,7 +9,7 @@ export class AgentSchedulerFactory implements IFluidDataStoreFactory {
|
|
|
9
9
|
// (undocumented)
|
|
10
10
|
static createChildInstance(parentContext: IFluidDataStoreContext): Promise<IAgentScheduler>;
|
|
11
11
|
// (undocumented)
|
|
12
|
-
get IFluidDataStoreFactory():
|
|
12
|
+
get IFluidDataStoreFactory(): AgentSchedulerFactory;
|
|
13
13
|
// (undocumented)
|
|
14
14
|
instantiateDataStore(context: IFluidDataStoreContext, existing: boolean): Promise<FluidDataStoreRuntime>;
|
|
15
15
|
// (undocumented)
|
package/dist/scheduler.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
6
|
-
import { IFluidHandle } from "@fluidframework/core-interfaces";
|
|
6
|
+
import type { IFluidHandle, IFluidLoadable } from "@fluidframework/core-interfaces";
|
|
7
7
|
import { FluidDataStoreRuntime } from "@fluidframework/datastore/internal";
|
|
8
8
|
import { IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions/internal";
|
|
9
9
|
import { ConsensusRegisterCollection } from "@fluidframework/register-collection/internal";
|
|
@@ -13,9 +13,9 @@ export declare class AgentScheduler extends TypedEventEmitter<IAgentSchedulerEve
|
|
|
13
13
|
private readonly runtime;
|
|
14
14
|
private readonly context;
|
|
15
15
|
private readonly consensusRegisterCollection;
|
|
16
|
-
static load(runtime: IFluidDataStoreRuntime, context: IFluidDataStoreContext, existing: boolean): Promise<
|
|
17
|
-
get IAgentScheduler():
|
|
18
|
-
get IFluidLoadable():
|
|
16
|
+
static load(runtime: IFluidDataStoreRuntime, context: IFluidDataStoreContext, existing: boolean): Promise<IAgentScheduler>;
|
|
17
|
+
get IAgentScheduler(): IAgentScheduler;
|
|
18
|
+
get IFluidLoadable(): IFluidLoadable;
|
|
19
19
|
private readonly logger;
|
|
20
20
|
private get clientId();
|
|
21
21
|
private readonly registeredTasks;
|
|
@@ -48,7 +48,7 @@ export declare class AgentScheduler extends TypedEventEmitter<IAgentSchedulerEve
|
|
|
48
48
|
export declare class AgentSchedulerFactory implements IFluidDataStoreFactory {
|
|
49
49
|
static readonly type = "_scheduler";
|
|
50
50
|
readonly type = "_scheduler";
|
|
51
|
-
get IFluidDataStoreFactory():
|
|
51
|
+
get IFluidDataStoreFactory(): AgentSchedulerFactory;
|
|
52
52
|
static get registryEntry(): NamedFluidDataStoreRegistryEntry;
|
|
53
53
|
static createChildInstance(parentContext: IFluidDataStoreContext): Promise<IAgentScheduler>;
|
|
54
54
|
instantiateDataStore(context: IFluidDataStoreContext, existing: boolean): Promise<FluidDataStoreRuntime>;
|
package/dist/scheduler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,KAAK,EAEX,YAAY,EACZ,cAAc,EAGd,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACN,qBAAqB,EAGrB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAEN,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AAExD,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,EACN,sBAAsB,EACtB,sBAAsB,EACtB,gCAAgC,EAChC,MAAM,8CAA8C,CAAC;AAStD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AA4BpE,qBAAa,cACZ,SAAQ,iBAAiB,CAAC,qBAAqB,CAC/C,YAAW,eAAe;IAmEzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,2BAA2B;WAnEzB,IAAI,CACvB,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,eAAe,CAAC;IAyB3B,IAAW,eAAe,IAAI,eAAe,CAE5C;IACD,IAAW,cAAc,IAAI,cAAc,CAE1C;IAED,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAE7C,OAAO,KAAK,QAAQ,GAOnB;IAMD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IAKrD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA0C;IAI/E,OAAO,CAAC,YAAY,CAAqB;IAEzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAG3B,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,EAC/B,2BAA2B,EAAE,2BAA2B,CAAC,MAAM,GAAG,IAAI,CAAC;IASzF,IAAW,MAAM,IAAI,YAAY,CAAC,IAAI,CAAC,CAEtC;IAEY,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBjE,OAAO,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BnD,WAAW,IAAI,MAAM,EAAE;YAIhB,YAAY;YAkBZ,WAAW;YAYX,UAAU;IASxB,OAAO,CAAC,eAAe;YAIT,SAAS;IAIvB,OAAO,CAAC,UAAU;IA+ElB,OAAO,CAAC,iBAAiB;YAcX,gBAAgB;IAwB9B,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,cAAc;CAGtB;AA2BD;;;GAGG;AACH,qBAAa,qBAAsB,YAAW,sBAAsB;IACnE,gBAAuB,IAAI,gBAAgB;IAC3C,SAAgB,IAAI,gBAA8B;IAElD,IAAW,sBAAsB,IAAI,qBAAqB,CAEzD;IAED,WAAkB,aAAa,IAAI,gCAAgC,CAElE;WAEmB,mBAAmB,CACtC,aAAa,EAAE,sBAAsB,GACnC,OAAO,CAAC,eAAe,CAAC;IAcd,oBAAoB,CAChC,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,qBAAqB,CAAC;CASjC"}
|
package/dist/scheduler.js
CHANGED
|
@@ -39,19 +39,20 @@ class AgentScheduler extends client_utils_1.TypedEventEmitter {
|
|
|
39
39
|
static async load(runtime, context, existing) {
|
|
40
40
|
let root;
|
|
41
41
|
let consensusRegisterCollection;
|
|
42
|
-
if (
|
|
42
|
+
if (existing) {
|
|
43
|
+
root = (await runtime.getChannel("root"));
|
|
44
|
+
const handle = await mapWait(root, schedulerId);
|
|
45
|
+
(0, internal_1.assert)(handle !== undefined, 0x116 /* "Missing handle on scheduler load" */);
|
|
46
|
+
consensusRegisterCollection = await handle.get();
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
43
49
|
root = internal_3.SharedMap.create(runtime, "root");
|
|
44
50
|
root.bindToContext();
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
45
52
|
consensusRegisterCollection = internal_4.ConsensusRegisterCollection.create(runtime);
|
|
46
53
|
consensusRegisterCollection.bindToContext();
|
|
47
54
|
root.set(schedulerId, consensusRegisterCollection.handle);
|
|
48
55
|
}
|
|
49
|
-
else {
|
|
50
|
-
root = (await runtime.getChannel("root"));
|
|
51
|
-
const handle = await mapWait(root, schedulerId);
|
|
52
|
-
(0, internal_1.assert)(handle !== undefined, 0x116 /* "Missing handle on scheduler load" */);
|
|
53
|
-
consensusRegisterCollection = await handle.get();
|
|
54
|
-
}
|
|
55
56
|
const agentScheduler = new AgentScheduler(runtime, context, consensusRegisterCollection);
|
|
56
57
|
agentScheduler.initialize();
|
|
57
58
|
return agentScheduler;
|
|
@@ -155,8 +156,9 @@ class AgentScheduler extends client_utils_1.TypedEventEmitter {
|
|
|
155
156
|
return this.releaseCore([...taskUrls]);
|
|
156
157
|
}
|
|
157
158
|
pickedTasks() {
|
|
158
|
-
return
|
|
159
|
+
return [...this.runningTasks.values()];
|
|
159
160
|
}
|
|
161
|
+
/* eslint-disable unicorn/no-null */
|
|
160
162
|
async registerCore(taskUrls) {
|
|
161
163
|
if (taskUrls.length > 0) {
|
|
162
164
|
const registersP = [];
|
|
@@ -307,6 +309,7 @@ class AgentScheduler extends client_utils_1.TypedEventEmitter {
|
|
|
307
309
|
}
|
|
308
310
|
}
|
|
309
311
|
}
|
|
312
|
+
/* eslint-enable unicorn/no-null */
|
|
310
313
|
isActive() {
|
|
311
314
|
// Scheduler should be active in detached container.
|
|
312
315
|
if (this.runtime.attachState === container_definitions_1.AttachState.Detached) {
|
|
@@ -363,12 +366,10 @@ class AgentSchedulerRuntime extends internal_2.FluidDataStoreRuntime {
|
|
|
363
366
|
}
|
|
364
367
|
async request(request) {
|
|
365
368
|
const response = await super.request(request);
|
|
366
|
-
if (response.status === 404) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
return { status: 200, mimeType: "fluid/object", value: agentScheduler };
|
|
371
|
-
}
|
|
369
|
+
if (response.status === 404 && (request.url === "" || request.url === "/")) {
|
|
370
|
+
const agentScheduler = await this.entryPoint.get();
|
|
371
|
+
(0, internal_1.assert)(agentScheduler !== undefined, 0x466 /* entryPoint for AgentSchedulerRuntime should have been initialized by now */);
|
|
372
|
+
return { status: 200, mimeType: "fluid/object", value: agentScheduler };
|
|
372
373
|
}
|
|
373
374
|
return response;
|
|
374
375
|
}
|
package/dist/scheduler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { FluidObject, IFluidHandle, IRequest } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tFluidDataStoreRuntime,\n\tFluidObjectHandle,\n\tISharedObjectRegistry,\n} from \"@fluidframework/datastore/internal\";\nimport {\n\tIChannelFactory,\n\tIFluidDataStoreRuntime,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { ISharedMap, IValueChanged, SharedMap } from \"@fluidframework/map/internal\";\nimport { ConsensusRegisterCollection } from \"@fluidframework/register-collection/internal\";\nimport {\n\tIFluidDataStoreContext,\n\tIFluidDataStoreFactory,\n\tNamedFluidDataStoreRegistryEntry,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tUsageError,\n\tcreateChildLogger,\n\ttagCodeArtifacts,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { IAgentScheduler, IAgentSchedulerEvents } from \"./agent.js\";\n\n// Note: making sure this ID is unique and does not collide with storage provided clientID\nconst UnattachedClientId = `${uuid()}_unattached`;\n\nconst mapWait = async <T = any>(map: ISharedMap, key: string): Promise<T> => {\n\tconst maybeValue = map.get<T>(key);\n\tif (maybeValue !== undefined) {\n\t\treturn maybeValue;\n\t}\n\n\treturn new Promise((resolve) => {\n\t\tconst handler = (changed: IValueChanged) => {\n\t\t\tif (changed.key === key) {\n\t\t\t\tmap.off(\"valueChanged\", handler);\n\t\t\t\tconst value = map.get<T>(changed.key);\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\tthrow new Error(\"Unexpected valueChanged result\");\n\t\t\t\t}\n\t\t\t\tresolve(value);\n\t\t\t}\n\t\t};\n\t\tmap.on(\"valueChanged\", handler);\n\t});\n};\n\nconst schedulerId = \"scheduler\";\n\nexport class AgentScheduler\n\textends TypedEventEmitter<IAgentSchedulerEvents>\n\timplements IAgentScheduler\n{\n\tpublic static async load(\n\t\truntime: IFluidDataStoreRuntime,\n\t\tcontext: IFluidDataStoreContext,\n\t\texisting: boolean,\n\t) {\n\t\tlet root: ISharedMap;\n\t\tlet consensusRegisterCollection: ConsensusRegisterCollection<string | null>;\n\t\tif (!existing) {\n\t\t\troot = SharedMap.create(runtime, \"root\");\n\t\t\troot.bindToContext();\n\t\t\tconsensusRegisterCollection = ConsensusRegisterCollection.create(runtime);\n\t\t\tconsensusRegisterCollection.bindToContext();\n\t\t\troot.set(schedulerId, consensusRegisterCollection.handle);\n\t\t} else {\n\t\t\troot = (await runtime.getChannel(\"root\")) as ISharedMap;\n\t\t\tconst handle = await mapWait<IFluidHandle<ConsensusRegisterCollection<string | null>>>(\n\t\t\t\troot,\n\t\t\t\tschedulerId,\n\t\t\t);\n\t\t\tassert(handle !== undefined, 0x116 /* \"Missing handle on scheduler load\" */);\n\t\t\tconsensusRegisterCollection = await handle.get();\n\t\t}\n\t\tconst agentScheduler = new AgentScheduler(runtime, context, consensusRegisterCollection);\n\t\tagentScheduler.initialize();\n\n\t\treturn agentScheduler;\n\t}\n\n\tpublic get IAgentScheduler() {\n\t\treturn this;\n\t}\n\tpublic get IFluidLoadable() {\n\t\treturn this;\n\t}\n\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tprivate get clientId(): string {\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\treturn UnattachedClientId;\n\t\t}\n\t\tconst clientId = this.runtime.clientId;\n\t\tassert(!!clientId, 0x117 /* \"Trying to get missing clientId!\" */);\n\t\treturn clientId;\n\t}\n\n\t// Set of tasks registered by this client.\n\t// Has no relationship with lists below.\n\t// The only requirement here - a task can be registered by a client only once.\n\t// Other clients can pick these tasks.\n\tprivate readonly registeredTasks = new Set<string>();\n\n\t// List of all tasks client is capable of running (essentially expressed desire to run)\n\t// Client will proactively attempt to pick them up these tasks if they are not assigned to other clients.\n\t// This is a strict superset of tasks running in the client.\n\tprivate readonly locallyRunnableTasks = new Map<string, () => Promise<void>>();\n\n\t// Set of registered tasks client is currently running.\n\t// It's subset of this.locallyRunnableTasks\n\tprivate runningTasks = new Set<string>();\n\n\tprivate readonly _handle: IFluidHandle<this>;\n\n\tconstructor(\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\t\tprivate readonly context: IFluidDataStoreContext,\n\t\tprivate readonly consensusRegisterCollection: ConsensusRegisterCollection<string | null>,\n\t) {\n\t\tsuper();\n\t\tthis.logger = createChildLogger({ logger: runtime.logger });\n\t\t// We are expecting this class to have many listeners, so we suppress noisy \"MaxListenersExceededWarning\" logging.\n\t\tsuper.setMaxListeners(0);\n\t\tthis._handle = new FluidObjectHandle(this, \"\", this.runtime.objectsRoutingContext);\n\t}\n\n\tpublic get handle() {\n\t\treturn this._handle;\n\t}\n\n\tpublic async register(...taskUrls: string[]): Promise<void> {\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tif (this.registeredTasks.has(taskUrl)) {\n\t\t\t\tthrow new UsageError(`Task is already registered`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t}\n\t\tconst unregisteredTasks: string[] = [];\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tthis.registeredTasks.add(taskUrl);\n\t\t\t// Only register for a new task.\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient === undefined) {\n\t\t\t\tunregisteredTasks.push(taskUrl);\n\t\t\t}\n\t\t}\n\t\treturn this.registerCore(unregisteredTasks);\n\t}\n\n\tpublic async pick(taskUrl: string, worker: () => Promise<void>): Promise<void> {\n\t\tif (this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\tthrow new UsageError(`Task is already attempted`, tagCodeArtifacts({ taskUrl }));\n\t\t}\n\t\tthis.locallyRunnableTasks.set(taskUrl, worker);\n\n\t\t// We have a policy to disallow non-interactive clients from taking tasks. Callers of pick() can\n\t\t// either perform this check proactively and call conditionally, or catch the error (in which case\n\t\t// they can know they will not get the task).\n\t\tassert(\n\t\t\tthis.context.deltaManager.clientDetails.capabilities.interactive,\n\t\t\t0x118 /* \"Bad client interactive check\" */,\n\t\t);\n\n\t\t// Check the current status and express interest if it's a new one (undefined) or currently unpicked (null).\n\t\tif (this.isActive()) {\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient === undefined || currentClient === null) {\n\t\t\t\tawait this.writeCore(taskUrl, this.clientId);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async release(...taskUrls: string[]): Promise<void> {\n\t\tconst active = this.isActive();\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tif (!this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\t\tthrow new UsageError(`Task was never registered`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t\tif (!this.runningTasks.has(taskUrl)) {\n\t\t\t\t// If we got disconnected (and are attached), tasks that we WERE picked for at the time of disconnect\n\t\t\t\t// will still show us as holding the task according to getTaskClientId (the CRC is stale), but we\n\t\t\t\t// should not try to release because our disconnect will already result in either someone else or\n\t\t\t\t// ourselves clearing the task upon reconnect.\n\t\t\t\t// This UsageError is to enforce that the caller should check AgentScheduler.pickedTasks before trying\n\t\t\t\t// to release a task.\n\t\t\t\tthrow new UsageError(`Task is not currently picked`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t\t// We may only release tasks that we KNOW we hold (detached state or connected and own the CRC). If we're\n\t\t\t// attached+disconnected then we'll lose the task automatically, and so may not release manually (someone\n\t\t\t// else might hold it by the time we reconnect)\n\t\t\tassert(active, 0x119 /* \"This agent became inactive while releasing\" */);\n\t\t\tif (this.getTaskClientId(taskUrl) !== this.clientId) {\n\t\t\t\tthrow new UsageError(`Task was never picked`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t}\n\t\treturn this.releaseCore([...taskUrls]);\n\t}\n\n\tpublic pickedTasks(): string[] {\n\t\treturn Array.from(this.runningTasks.values());\n\t}\n\n\tprivate async registerCore(taskUrls: string[]): Promise<void> {\n\t\tif (taskUrls.length > 0) {\n\t\t\tconst registersP: Promise<void>[] = [];\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\tregistersP.push(this.writeCore(taskUrl, null));\n\t\t\t}\n\t\t\tawait Promise.all(registersP);\n\n\t\t\t// The registers should have up to date results now. Check the status.\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\tconst taskStatus = this.getTaskClientId(taskUrl);\n\n\t\t\t\t// Task should be either registered (null) or picked up.\n\t\t\t\tassert(taskStatus !== undefined, 0x11a /* `Unsuccessful registration` */);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async releaseCore(taskUrls: string[]) {\n\t\tif (taskUrls.length > 0) {\n\t\t\tconst releasesP: Promise<void>[] = [];\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\t// Remove from local map so that it can be picked later.\n\t\t\t\tthis.locallyRunnableTasks.delete(taskUrl);\n\t\t\t\treleasesP.push(this.writeCore(taskUrl, null));\n\t\t\t}\n\t\t\tawait Promise.all(releasesP);\n\t\t}\n\t}\n\n\tprivate async clearTasks(taskUrls: string[]) {\n\t\tassert(this.isActive(), 0x11b /* \"Trying to clear tasks on inactive agent\" */);\n\t\tconst clearP: Promise<void>[] = [];\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tclearP.push(this.writeCore(taskUrl, null));\n\t\t}\n\t\tawait Promise.all(clearP);\n\t}\n\n\tprivate getTaskClientId(url: string): string | null | undefined {\n\t\treturn this.consensusRegisterCollection.read(url);\n\t}\n\n\tprivate async writeCore(key: string, clientId: string | null): Promise<void> {\n\t\tawait this.consensusRegisterCollection.write(key, clientId);\n\t}\n\n\tprivate initialize() {\n\t\tconst quorum = this.runtime.getQuorum();\n\t\t// A client left the quorum. Iterate and clear tasks held by that client.\n\t\t// Ideally a leader should do this cleanup. But it's complicated when a leader itself leaves.\n\t\t// Probably okay for now to have every client try to do this.\n\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\tquorum.on(\"removeMember\", async (clientId: string) => {\n\t\t\t// TODO AB#19980: The scenario with a detached routing context is not fully supported.\n\t\t\tif (!this.runtime.objectsRoutingContext.isAttached) return;\n\t\t\t// Cleanup only if connected. If not, cleanup will happen in initializeCore() that runs on connection.\n\t\t\tif (this.isActive()) {\n\t\t\t\tconst tasks: Promise<any>[] = [];\n\t\t\t\tconst leftTasks: string[] = [];\n\t\t\t\tfor (const taskUrl of this.consensusRegisterCollection.keys()) {\n\t\t\t\t\tif (this.getTaskClientId(taskUrl) === clientId) {\n\t\t\t\t\t\tif (this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\t\t\t\t\ttasks.push(this.writeCore(taskUrl, this.clientId));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tleftTasks.push(taskUrl);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttasks.push(this.clearTasks(leftTasks));\n\t\t\t\tawait Promise.all(tasks).catch((error) => {\n\t\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_RemoveMemberError\", error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t// Listeners for new/released tasks. All clients will try to grab at the same time.\n\t\t// May be we want a randomized timer (Something like raft) to reduce chattiness?\n\t\tthis.consensusRegisterCollection.on(\n\t\t\t\"atomicChanged\",\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\t\tasync (key: string, currentClient: string | null) => {\n\t\t\t\t// Check if this client was chosen.\n\t\t\t\tif (this.isActive() && currentClient === this.clientId) {\n\t\t\t\t\tthis.onNewTaskAssigned(key);\n\t\t\t\t} else {\n\t\t\t\t\t// The call below mutates the consensusRegisterCollection in\n\t\t\t\t\t// its event handler, which is not safe.\n\t\t\t\t\t// We need to force this to be part of a different batch of ops by\n\t\t\t\t\t// scheduling a microtask in order to work around the current validations.\n\t\t\t\t\t// This is not recommended and should be avoided.\n\t\t\t\t\tawait Promise.resolve().then(async () => {\n\t\t\t\t\t\tawait this.onTaskReassigned(key, currentClient);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (this.isActive()) {\n\t\t\tthis.initializeCore();\n\t\t}\n\n\t\tthis.runtime.on(\"connected\", () => {\n\t\t\tif (this.isActive()) {\n\t\t\t\tthis.initializeCore();\n\t\t\t}\n\t\t});\n\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\tthis.runtime\n\t\t\t\t.waitAttached()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.clearRunningTasks();\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_clearRunningTasks\", error);\n\t\t\t\t});\n\t\t}\n\n\t\tthis.runtime.on(\"disconnected\", () => {\n\t\t\tif (this.runtime.attachState !== AttachState.Detached) {\n\t\t\t\tthis.clearRunningTasks();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate onNewTaskAssigned(key: string) {\n\t\tassert(!this.runningTasks.has(key), 0x11d /* \"task is already running\" */);\n\t\tthis.runningTasks.add(key);\n\t\tconst worker = this.locallyRunnableTasks.get(key);\n\t\tif (worker === undefined) {\n\t\t\tthis.sendErrorEvent(\"AgentScheduler_UnwantedChange\", undefined, key);\n\t\t} else {\n\t\t\tthis.emit(\"picked\", key);\n\t\t\tworker().catch((error) => {\n\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_FailedWork\", error, key);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async onTaskReassigned(key: string, currentClient: string | null) {\n\t\tif (this.runningTasks.has(key)) {\n\t\t\tthis.runningTasks.delete(key);\n\t\t\tthis.emit(\"released\", key);\n\t\t}\n\t\tassert(currentClient !== undefined, 0x11e /* \"client is undefined\" */);\n\t\tif (this.isActive()) {\n\t\t\t// attempt to pick up task if we are connected.\n\t\t\t// If not, initializeCore() will do it when connected\n\t\t\tif (currentClient === null) {\n\t\t\t\tif (this.locallyRunnableTasks.has(key)) {\n\t\t\t\t\tawait this.writeCore(key, this.clientId);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Check if the op came from dropped client\n\t\t\t// This could happen when \"old\" ops are submitted on reconnection.\n\t\t\t// They carry \"old\" ref seq number, but if write is not contested, it will get accepted\n\t\t\telse if (this.runtime.getQuorum().getMember(currentClient) === undefined) {\n\t\t\t\tawait this.writeCore(key, null);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isActive() {\n\t\t// Scheduler should be active in detached container.\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!this.runtime.connected) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note: we are not checking for this.context.deltaManager.clientDetails.capabilities.interactive\n\t\t// here. Instead we assert in pick() if a non-interactive client tries to pick.\n\n\t\treturn this.context.deltaManager.active;\n\t}\n\n\tprivate initializeCore() {\n\t\t// Nobody released the tasks held by last client in previous session.\n\t\t// Check to see if this client needs to do this.\n\t\tconst clearCandidates: string[] = [];\n\t\tconst tasks: Promise<any>[] = [];\n\n\t\tfor (const [taskUrl] of this.locallyRunnableTasks) {\n\t\t\tif (!this.getTaskClientId(taskUrl)) {\n\t\t\t\ttasks.push(this.writeCore(taskUrl, this.clientId));\n\t\t\t}\n\t\t}\n\n\t\tfor (const taskUrl of this.consensusRegisterCollection.keys()) {\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient && this.runtime.getQuorum().getMember(currentClient) === undefined) {\n\t\t\t\tclearCandidates.push(taskUrl);\n\t\t\t}\n\t\t}\n\n\t\ttasks.push(this.clearTasks(clearCandidates));\n\n\t\tPromise.all(tasks).catch((error) => {\n\t\t\tthis.sendErrorEvent(\"AgentScheduler_InitError\", error);\n\t\t});\n\t}\n\n\tprivate clearRunningTasks() {\n\t\tconst tasks = this.runningTasks;\n\t\tthis.runningTasks = new Set<string>();\n\n\t\tif (this.isActive()) {\n\t\t\t// Clear all tasks with UnattachedClientId (if was unattached) and reapply for tasks with new clientId\n\t\t\t// If we are simply disconnected, then proper cleanup will be done on connection.\n\t\t\tthis.initializeCore();\n\t\t}\n\n\t\tfor (const task of tasks) {\n\t\t\tthis.emit(\"lost\", task);\n\t\t}\n\t}\n\n\tprivate sendErrorEvent(eventName: string, error: any, key?: string) {\n\t\tthis.logger.sendErrorEvent({ eventName, key }, error);\n\t}\n}\n\nclass AgentSchedulerRuntime extends FluidDataStoreRuntime {\n\tconstructor(\n\t\tdataStoreContext: IFluidDataStoreContext,\n\t\tsharedObjectRegistry: ISharedObjectRegistry,\n\t\texisting: boolean,\n\t) {\n\t\tsuper(dataStoreContext, sharedObjectRegistry, existing, async () =>\n\t\t\tAgentScheduler.load(this, dataStoreContext, existing),\n\t\t);\n\t}\n\tpublic async request(request: IRequest) {\n\t\tconst response = await super.request(request);\n\t\tif (response.status === 404) {\n\t\t\tif (request.url === \"\" || request.url === \"/\") {\n\t\t\t\tconst agentScheduler = await this.entryPoint.get();\n\t\t\t\tassert(\n\t\t\t\t\tagentScheduler !== undefined,\n\t\t\t\t\t0x466 /* entryPoint for AgentSchedulerRuntime should have been initialized by now */,\n\t\t\t\t);\n\n\t\t\t\treturn { status: 200, mimeType: \"fluid/object\", value: agentScheduler };\n\t\t\t}\n\t\t}\n\t\treturn response;\n\t}\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport class AgentSchedulerFactory implements IFluidDataStoreFactory {\n\tpublic static readonly type = \"_scheduler\";\n\tpublic readonly type = AgentSchedulerFactory.type;\n\n\tpublic get IFluidDataStoreFactory() {\n\t\treturn this;\n\t}\n\n\tpublic static get registryEntry(): NamedFluidDataStoreRegistryEntry {\n\t\treturn [this.type, Promise.resolve(new AgentSchedulerFactory())];\n\t}\n\n\tpublic static async createChildInstance(\n\t\tparentContext: IFluidDataStoreContext,\n\t): Promise<IAgentScheduler> {\n\t\tconst packagePath = [...parentContext.packagePath, AgentSchedulerFactory.type];\n\t\tconst dataStore = await parentContext.containerRuntime.createDataStore(packagePath);\n\t\tconst entryPoint: FluidObject<IAgentScheduler> = await dataStore.entryPoint.get();\n\n\t\t// AgentSchedulerRuntime always puts an AgentScheduler object in the data store's entryPoint, but double-check\n\t\t// while we plumb entryPoints correctly everywhere, so we can be sure the cast below is fine.\n\t\tassert(\n\t\t\tentryPoint.IAgentScheduler !== undefined,\n\t\t\t0x467 /* The data store's entryPoint is not an AgentScheduler! */,\n\t\t);\n\t\treturn entryPoint as unknown as AgentScheduler;\n\t}\n\n\tpublic async instantiateDataStore(\n\t\tcontext: IFluidDataStoreContext,\n\t\texisting: boolean,\n\t): Promise<FluidDataStoreRuntime> {\n\t\tconst mapFactory = SharedMap.getFactory();\n\t\tconst consensusRegisterCollectionFactory = ConsensusRegisterCollection.getFactory();\n\t\tconst dataTypes = new Map<string, IChannelFactory>();\n\t\tdataTypes.set(mapFactory.type, mapFactory);\n\t\tdataTypes.set(consensusRegisterCollectionFactory.type, consensusRegisterCollectionFactory);\n\n\t\treturn new AgentSchedulerRuntime(context, dataTypes, existing);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport type {\n\tFluidObject,\n\tIFluidHandle,\n\tIFluidLoadable,\n\tIRequest,\n\tIResponse,\n} from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tFluidDataStoreRuntime,\n\tFluidObjectHandle,\n\tISharedObjectRegistry,\n} from \"@fluidframework/datastore/internal\";\nimport {\n\tIChannelFactory,\n\tIFluidDataStoreRuntime,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { ISharedMap, IValueChanged, SharedMap } from \"@fluidframework/map/internal\";\nimport { ConsensusRegisterCollection } from \"@fluidframework/register-collection/internal\";\nimport {\n\tIFluidDataStoreContext,\n\tIFluidDataStoreFactory,\n\tNamedFluidDataStoreRegistryEntry,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tUsageError,\n\tcreateChildLogger,\n\ttagCodeArtifacts,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { IAgentScheduler, IAgentSchedulerEvents } from \"./agent.js\";\n\n// Note: making sure this ID is unique and does not collide with storage provided clientID\nconst UnattachedClientId = `${uuid()}_unattached`;\n\nconst mapWait = async <T = unknown>(map: ISharedMap, key: string): Promise<T> => {\n\tconst maybeValue = map.get<T>(key);\n\tif (maybeValue !== undefined) {\n\t\treturn maybeValue;\n\t}\n\n\treturn new Promise((resolve) => {\n\t\tconst handler = (changed: IValueChanged): void => {\n\t\t\tif (changed.key === key) {\n\t\t\t\tmap.off(\"valueChanged\", handler);\n\t\t\t\tconst value = map.get<T>(changed.key);\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\tthrow new Error(\"Unexpected valueChanged result\");\n\t\t\t\t}\n\t\t\t\tresolve(value);\n\t\t\t}\n\t\t};\n\t\tmap.on(\"valueChanged\", handler);\n\t});\n};\n\nconst schedulerId = \"scheduler\";\n\nexport class AgentScheduler\n\textends TypedEventEmitter<IAgentSchedulerEvents>\n\timplements IAgentScheduler\n{\n\tpublic static async load(\n\t\truntime: IFluidDataStoreRuntime,\n\t\tcontext: IFluidDataStoreContext,\n\t\texisting: boolean,\n\t): Promise<IAgentScheduler> {\n\t\tlet root: ISharedMap;\n\t\tlet consensusRegisterCollection: ConsensusRegisterCollection<string | null>;\n\t\tif (existing) {\n\t\t\troot = (await runtime.getChannel(\"root\")) as ISharedMap;\n\t\t\tconst handle = await mapWait<IFluidHandle<ConsensusRegisterCollection<string | null>>>(\n\t\t\t\troot,\n\t\t\t\tschedulerId,\n\t\t\t);\n\t\t\tassert(handle !== undefined, 0x116 /* \"Missing handle on scheduler load\" */);\n\t\t\tconsensusRegisterCollection = await handle.get();\n\t\t} else {\n\t\t\troot = SharedMap.create(runtime, \"root\");\n\t\t\troot.bindToContext();\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconsensusRegisterCollection = ConsensusRegisterCollection.create(runtime);\n\t\t\tconsensusRegisterCollection.bindToContext();\n\t\t\troot.set(schedulerId, consensusRegisterCollection.handle);\n\t\t}\n\t\tconst agentScheduler = new AgentScheduler(runtime, context, consensusRegisterCollection);\n\t\tagentScheduler.initialize();\n\n\t\treturn agentScheduler;\n\t}\n\n\tpublic get IAgentScheduler(): IAgentScheduler {\n\t\treturn this;\n\t}\n\tpublic get IFluidLoadable(): IFluidLoadable {\n\t\treturn this;\n\t}\n\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tprivate get clientId(): string {\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\treturn UnattachedClientId;\n\t\t}\n\t\tconst clientId = this.runtime.clientId;\n\t\tassert(!!clientId, 0x117 /* \"Trying to get missing clientId!\" */);\n\t\treturn clientId;\n\t}\n\n\t// Set of tasks registered by this client.\n\t// Has no relationship with lists below.\n\t// The only requirement here - a task can be registered by a client only once.\n\t// Other clients can pick these tasks.\n\tprivate readonly registeredTasks = new Set<string>();\n\n\t// List of all tasks client is capable of running (essentially expressed desire to run)\n\t// Client will proactively attempt to pick them up these tasks if they are not assigned to other clients.\n\t// This is a strict superset of tasks running in the client.\n\tprivate readonly locallyRunnableTasks = new Map<string, () => Promise<void>>();\n\n\t// Set of registered tasks client is currently running.\n\t// It's subset of this.locallyRunnableTasks\n\tprivate runningTasks = new Set<string>();\n\n\tprivate readonly _handle: IFluidHandle<this>;\n\n\tconstructor(\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\t\tprivate readonly context: IFluidDataStoreContext,\n\t\tprivate readonly consensusRegisterCollection: ConsensusRegisterCollection<string | null>,\n\t) {\n\t\tsuper();\n\t\tthis.logger = createChildLogger({ logger: runtime.logger });\n\t\t// We are expecting this class to have many listeners, so we suppress noisy \"MaxListenersExceededWarning\" logging.\n\t\tsuper.setMaxListeners(0);\n\t\tthis._handle = new FluidObjectHandle(this, \"\", this.runtime.objectsRoutingContext);\n\t}\n\n\tpublic get handle(): IFluidHandle<this> {\n\t\treturn this._handle;\n\t}\n\n\tpublic async register(...taskUrls: string[]): Promise<void> {\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tif (this.registeredTasks.has(taskUrl)) {\n\t\t\t\tthrow new UsageError(`Task is already registered`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t}\n\t\tconst unregisteredTasks: string[] = [];\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tthis.registeredTasks.add(taskUrl);\n\t\t\t// Only register for a new task.\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient === undefined) {\n\t\t\t\tunregisteredTasks.push(taskUrl);\n\t\t\t}\n\t\t}\n\t\treturn this.registerCore(unregisteredTasks);\n\t}\n\n\tpublic async pick(taskUrl: string, worker: () => Promise<void>): Promise<void> {\n\t\tif (this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\tthrow new UsageError(`Task is already attempted`, tagCodeArtifacts({ taskUrl }));\n\t\t}\n\t\tthis.locallyRunnableTasks.set(taskUrl, worker);\n\n\t\t// We have a policy to disallow non-interactive clients from taking tasks. Callers of pick() can\n\t\t// either perform this check proactively and call conditionally, or catch the error (in which case\n\t\t// they can know they will not get the task).\n\t\tassert(\n\t\t\tthis.context.deltaManager.clientDetails.capabilities.interactive,\n\t\t\t0x118 /* \"Bad client interactive check\" */,\n\t\t);\n\n\t\t// Check the current status and express interest if it's a new one (undefined) or currently unpicked (null).\n\t\tif (this.isActive()) {\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient === undefined || currentClient === null) {\n\t\t\t\tawait this.writeCore(taskUrl, this.clientId);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async release(...taskUrls: string[]): Promise<void> {\n\t\tconst active = this.isActive();\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tif (!this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\t\tthrow new UsageError(`Task was never registered`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t\tif (!this.runningTasks.has(taskUrl)) {\n\t\t\t\t// If we got disconnected (and are attached), tasks that we WERE picked for at the time of disconnect\n\t\t\t\t// will still show us as holding the task according to getTaskClientId (the CRC is stale), but we\n\t\t\t\t// should not try to release because our disconnect will already result in either someone else or\n\t\t\t\t// ourselves clearing the task upon reconnect.\n\t\t\t\t// This UsageError is to enforce that the caller should check AgentScheduler.pickedTasks before trying\n\t\t\t\t// to release a task.\n\t\t\t\tthrow new UsageError(`Task is not currently picked`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t\t// We may only release tasks that we KNOW we hold (detached state or connected and own the CRC). If we're\n\t\t\t// attached+disconnected then we'll lose the task automatically, and so may not release manually (someone\n\t\t\t// else might hold it by the time we reconnect)\n\t\t\tassert(active, 0x119 /* \"This agent became inactive while releasing\" */);\n\t\t\tif (this.getTaskClientId(taskUrl) !== this.clientId) {\n\t\t\t\tthrow new UsageError(`Task was never picked`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t}\n\t\treturn this.releaseCore([...taskUrls]);\n\t}\n\n\tpublic pickedTasks(): string[] {\n\t\treturn [...this.runningTasks.values()];\n\t}\n\t/* eslint-disable unicorn/no-null */\n\tprivate async registerCore(taskUrls: string[]): Promise<void> {\n\t\tif (taskUrls.length > 0) {\n\t\t\tconst registersP: Promise<void>[] = [];\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\tregistersP.push(this.writeCore(taskUrl, null));\n\t\t\t}\n\t\t\tawait Promise.all(registersP);\n\n\t\t\t// The registers should have up to date results now. Check the status.\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\tconst taskStatus = this.getTaskClientId(taskUrl);\n\n\t\t\t\t// Task should be either registered (null) or picked up.\n\t\t\t\tassert(taskStatus !== undefined, 0x11a /* `Unsuccessful registration` */);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async releaseCore(taskUrls: string[]): Promise<void> {\n\t\tif (taskUrls.length > 0) {\n\t\t\tconst releasesP: Promise<void>[] = [];\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\t// Remove from local map so that it can be picked later.\n\t\t\t\tthis.locallyRunnableTasks.delete(taskUrl);\n\t\t\t\treleasesP.push(this.writeCore(taskUrl, null));\n\t\t\t}\n\t\t\tawait Promise.all(releasesP);\n\t\t}\n\t}\n\n\tprivate async clearTasks(taskUrls: string[]): Promise<void> {\n\t\tassert(this.isActive(), 0x11b /* \"Trying to clear tasks on inactive agent\" */);\n\t\tconst clearP: Promise<void>[] = [];\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tclearP.push(this.writeCore(taskUrl, null));\n\t\t}\n\t\tawait Promise.all(clearP);\n\t}\n\n\tprivate getTaskClientId(url: string): string | null | undefined {\n\t\treturn this.consensusRegisterCollection.read(url);\n\t}\n\n\tprivate async writeCore(key: string, clientId: string | null): Promise<void> {\n\t\tawait this.consensusRegisterCollection.write(key, clientId);\n\t}\n\n\tprivate initialize(): void {\n\t\tconst quorum = this.runtime.getQuorum();\n\t\t// A client left the quorum. Iterate and clear tasks held by that client.\n\t\t// Ideally a leader should do this cleanup. But it's complicated when a leader itself leaves.\n\t\t// Probably okay for now to have every client try to do this.\n\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\tquorum.on(\"removeMember\", async (clientId: string) => {\n\t\t\t// TODO AB#19980: The scenario with a detached routing context is not fully supported.\n\t\t\tif (!this.runtime.objectsRoutingContext.isAttached) return;\n\t\t\t// Cleanup only if connected. If not, cleanup will happen in initializeCore() that runs on connection.\n\t\t\tif (this.isActive()) {\n\t\t\t\tconst tasks: Promise<unknown>[] = [];\n\t\t\t\tconst leftTasks: string[] = [];\n\t\t\t\tfor (const taskUrl of this.consensusRegisterCollection.keys()) {\n\t\t\t\t\tif (this.getTaskClientId(taskUrl) === clientId) {\n\t\t\t\t\t\tif (this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\t\t\t\t\ttasks.push(this.writeCore(taskUrl, this.clientId));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tleftTasks.push(taskUrl);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttasks.push(this.clearTasks(leftTasks));\n\t\t\t\tawait Promise.all(tasks).catch((error) => {\n\t\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_RemoveMemberError\", error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t// Listeners for new/released tasks. All clients will try to grab at the same time.\n\t\t// May be we want a randomized timer (Something like raft) to reduce chattiness?\n\t\tthis.consensusRegisterCollection.on(\n\t\t\t\"atomicChanged\",\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\t\tasync (key: string, currentClient: string | null) => {\n\t\t\t\t// Check if this client was chosen.\n\t\t\t\tif (this.isActive() && currentClient === this.clientId) {\n\t\t\t\t\tthis.onNewTaskAssigned(key);\n\t\t\t\t} else {\n\t\t\t\t\t// The call below mutates the consensusRegisterCollection in\n\t\t\t\t\t// its event handler, which is not safe.\n\t\t\t\t\t// We need to force this to be part of a different batch of ops by\n\t\t\t\t\t// scheduling a microtask in order to work around the current validations.\n\t\t\t\t\t// This is not recommended and should be avoided.\n\t\t\t\t\tawait Promise.resolve().then(async () => {\n\t\t\t\t\t\tawait this.onTaskReassigned(key, currentClient);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (this.isActive()) {\n\t\t\tthis.initializeCore();\n\t\t}\n\n\t\tthis.runtime.on(\"connected\", () => {\n\t\t\tif (this.isActive()) {\n\t\t\t\tthis.initializeCore();\n\t\t\t}\n\t\t});\n\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\tthis.runtime\n\t\t\t\t.waitAttached()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.clearRunningTasks();\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_clearRunningTasks\", error);\n\t\t\t\t});\n\t\t}\n\n\t\tthis.runtime.on(\"disconnected\", () => {\n\t\t\tif (this.runtime.attachState !== AttachState.Detached) {\n\t\t\t\tthis.clearRunningTasks();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate onNewTaskAssigned(key: string): void {\n\t\tassert(!this.runningTasks.has(key), 0x11d /* \"task is already running\" */);\n\t\tthis.runningTasks.add(key);\n\t\tconst worker = this.locallyRunnableTasks.get(key);\n\t\tif (worker === undefined) {\n\t\t\tthis.sendErrorEvent(\"AgentScheduler_UnwantedChange\", undefined, key);\n\t\t} else {\n\t\t\tthis.emit(\"picked\", key);\n\t\t\tworker().catch((error) => {\n\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_FailedWork\", error, key);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async onTaskReassigned(key: string, currentClient: string | null): Promise<void> {\n\t\tif (this.runningTasks.has(key)) {\n\t\t\tthis.runningTasks.delete(key);\n\t\t\tthis.emit(\"released\", key);\n\t\t}\n\t\tassert(currentClient !== undefined, 0x11e /* \"client is undefined\" */);\n\t\tif (this.isActive()) {\n\t\t\t// attempt to pick up task if we are connected.\n\t\t\t// If not, initializeCore() will do it when connected\n\t\t\tif (currentClient === null) {\n\t\t\t\tif (this.locallyRunnableTasks.has(key)) {\n\t\t\t\t\tawait this.writeCore(key, this.clientId);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Check if the op came from dropped client\n\t\t\t// This could happen when \"old\" ops are submitted on reconnection.\n\t\t\t// They carry \"old\" ref seq number, but if write is not contested, it will get accepted\n\t\t\telse if (this.runtime.getQuorum().getMember(currentClient) === undefined) {\n\t\t\t\tawait this.writeCore(key, null);\n\t\t\t}\n\t\t}\n\t}\n\t/* eslint-enable unicorn/no-null */\n\n\tprivate isActive(): boolean {\n\t\t// Scheduler should be active in detached container.\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!this.runtime.connected) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note: we are not checking for this.context.deltaManager.clientDetails.capabilities.interactive\n\t\t// here. Instead we assert in pick() if a non-interactive client tries to pick.\n\n\t\treturn this.context.deltaManager.active;\n\t}\n\n\tprivate initializeCore(): void {\n\t\t// Nobody released the tasks held by last client in previous session.\n\t\t// Check to see if this client needs to do this.\n\t\tconst clearCandidates: string[] = [];\n\t\tconst tasks: Promise<unknown>[] = [];\n\n\t\tfor (const [taskUrl] of this.locallyRunnableTasks) {\n\t\t\tif (!this.getTaskClientId(taskUrl)) {\n\t\t\t\ttasks.push(this.writeCore(taskUrl, this.clientId));\n\t\t\t}\n\t\t}\n\n\t\tfor (const taskUrl of this.consensusRegisterCollection.keys()) {\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient && this.runtime.getQuorum().getMember(currentClient) === undefined) {\n\t\t\t\tclearCandidates.push(taskUrl);\n\t\t\t}\n\t\t}\n\n\t\ttasks.push(this.clearTasks(clearCandidates));\n\n\t\tPromise.all(tasks).catch((error) => {\n\t\t\tthis.sendErrorEvent(\"AgentScheduler_InitError\", error);\n\t\t});\n\t}\n\n\tprivate clearRunningTasks(): void {\n\t\tconst tasks = this.runningTasks;\n\t\tthis.runningTasks = new Set<string>();\n\n\t\tif (this.isActive()) {\n\t\t\t// Clear all tasks with UnattachedClientId (if was unattached) and reapply for tasks with new clientId\n\t\t\t// If we are simply disconnected, then proper cleanup will be done on connection.\n\t\t\tthis.initializeCore();\n\t\t}\n\n\t\tfor (const task of tasks) {\n\t\t\tthis.emit(\"lost\", task);\n\t\t}\n\t}\n\n\tprivate sendErrorEvent(eventName: string, error: unknown, key?: string): void {\n\t\tthis.logger.sendErrorEvent({ eventName, key }, error);\n\t}\n}\n\nclass AgentSchedulerRuntime extends FluidDataStoreRuntime {\n\tconstructor(\n\t\tdataStoreContext: IFluidDataStoreContext,\n\t\tsharedObjectRegistry: ISharedObjectRegistry,\n\t\texisting: boolean,\n\t) {\n\t\tsuper(dataStoreContext, sharedObjectRegistry, existing, async () =>\n\t\t\tAgentScheduler.load(this, dataStoreContext, existing),\n\t\t);\n\t}\n\tpublic async request(request: IRequest): Promise<IResponse> {\n\t\tconst response = await super.request(request);\n\t\tif (response.status === 404 && (request.url === \"\" || request.url === \"/\")) {\n\t\t\tconst agentScheduler = await this.entryPoint.get();\n\t\t\tassert(\n\t\t\t\tagentScheduler !== undefined,\n\t\t\t\t0x466 /* entryPoint for AgentSchedulerRuntime should have been initialized by now */,\n\t\t\t);\n\n\t\t\treturn { status: 200, mimeType: \"fluid/object\", value: agentScheduler };\n\t\t}\n\t\treturn response;\n\t}\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport class AgentSchedulerFactory implements IFluidDataStoreFactory {\n\tpublic static readonly type = \"_scheduler\";\n\tpublic readonly type = AgentSchedulerFactory.type;\n\n\tpublic get IFluidDataStoreFactory(): AgentSchedulerFactory {\n\t\treturn this;\n\t}\n\n\tpublic static get registryEntry(): NamedFluidDataStoreRegistryEntry {\n\t\treturn [this.type, Promise.resolve(new AgentSchedulerFactory())];\n\t}\n\n\tpublic static async createChildInstance(\n\t\tparentContext: IFluidDataStoreContext,\n\t): Promise<IAgentScheduler> {\n\t\tconst packagePath = [...parentContext.packagePath, AgentSchedulerFactory.type];\n\t\tconst dataStore = await parentContext.containerRuntime.createDataStore(packagePath);\n\t\tconst entryPoint: FluidObject<IAgentScheduler> = await dataStore.entryPoint.get();\n\n\t\t// AgentSchedulerRuntime always puts an AgentScheduler object in the data store's entryPoint, but double-check\n\t\t// while we plumb entryPoints correctly everywhere, so we can be sure the cast below is fine.\n\t\tassert(\n\t\t\tentryPoint.IAgentScheduler !== undefined,\n\t\t\t0x467 /* The data store's entryPoint is not an AgentScheduler! */,\n\t\t);\n\t\treturn entryPoint as unknown as AgentScheduler;\n\t}\n\n\tpublic async instantiateDataStore(\n\t\tcontext: IFluidDataStoreContext,\n\t\texisting: boolean,\n\t): Promise<FluidDataStoreRuntime> {\n\t\tconst mapFactory = SharedMap.getFactory();\n\t\tconst consensusRegisterCollectionFactory = ConsensusRegisterCollection.getFactory();\n\t\tconst dataTypes = new Map<string, IChannelFactory>();\n\t\tdataTypes.set(mapFactory.type, mapFactory);\n\t\tdataTypes.set(consensusRegisterCollectionFactory.type, consensusRegisterCollectionFactory);\n\n\t\treturn new AgentSchedulerRuntime(context, dataTypes, existing);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taskSubscription.d.ts","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,uBAAwB,SAAQ,MAAM;IACtD,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CACtD;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,iBAAiB,CAAC,uBAAuB,CAAC;IAQ9E,OAAO,CAAC,QAAQ,CAAC,cAAc;aACf,MAAM,EAAE,MAAM;IAR/B,OAAO,CAAC,UAAU,CAAkB;IAEpC;;;OAGG;gBAEe,cAAc,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM;IAoB/B;;;OAGG;IACI,QAAQ;
|
|
1
|
+
{"version":3,"file":"taskSubscription.d.ts","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,uBAAwB,SAAQ,MAAM;IACtD,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CACtD;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,iBAAiB,CAAC,uBAAuB,CAAC;IAQ9E,OAAO,CAAC,QAAQ,CAAC,cAAc;aACf,MAAM,EAAE,MAAM;IAR/B,OAAO,CAAC,UAAU,CAAkB;IAEpC;;;OAGG;gBAEe,cAAc,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM;IAoB/B;;;OAGG;IACI,QAAQ,IAAI,OAAO;IAI1B;;;OAGG;IACI,SAAS,IAAI,IAAI;CAUxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taskSubscription.js","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAiE;AAcjE;;;;GAIG;AACH,MAAa,gBAAiB,SAAQ,gCAA0C;IAG/E;;;OAGG;IACH,YACkB,cAA+B,EAChC,MAAc;QAE9B,KAAK,EAAE,CAAC;QAHS,mBAAc,GAAd,cAAc,CAAiB;QAChC,WAAM,GAAN,MAAM,CAAQ;QARvB,eAAU,GAAY,KAAK,CAAC;QAWnC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAe,EAAE,EAAE;YAC/C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,CAAC;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,OAAe,EAAE,EAAE;YACjD,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAe,EAAE,EAAE;YAC7C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,OAAO,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACtB,uFAAuF;YACvF,gFAAgF;YAChF,0FAA0F;YAC1F,qCAAqC;YACrC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACxB,CAAC;IACF,CAAC;CACD;AAnDD,4CAmDC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { IEvent } from \"@fluidframework/core-interfaces\";\n\nimport { IAgentScheduler } from \"./agent.js\";\n\n/**\n * Events emitted by {@link TaskSubscription}.\n * @legacy\n * @alpha\n */\nexport interface ITaskSubscriptionEvents extends IEvent {\n\t(event: \"gotTask\" | \"lostTask\", listener: () => void);\n}\n\n/**\n * TaskSubscription works with an AgentScheduler to make it easier to monitor a specific task ownership.\n * @legacy\n * @alpha\n */\nexport class TaskSubscription extends TypedEventEmitter<ITaskSubscriptionEvents> {\n\tprivate subscribed: boolean = false;\n\n\t/**\n\t * @param agentScheduler - The AgentScheduler that will be subscribed against\n\t * @param taskId - The string ID of the task to subscribe against\n\t */\n\tconstructor(\n\t\tprivate readonly agentScheduler: IAgentScheduler,\n\t\tpublic readonly taskId: string,\n\t) {\n\t\tsuper();\n\t\tagentScheduler.on(\"picked\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"gotTask\");\n\t\t\t}\n\t\t});\n\t\tagentScheduler.on(\"released\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"lostTask\");\n\t\t\t}\n\t\t});\n\t\tagentScheduler.on(\"lost\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"lostTask\");\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Check if currently holding ownership of the task.\n\t * @returns true if currently the task owner, false otherwise.\n\t */\n\tpublic haveTask() {\n\t\treturn this.agentScheduler.pickedTasks().includes(this.taskId);\n\t}\n\n\t/**\n\t * Volunteer for the task. By default, the TaskSubscription will only watch the task and not volunteer.\n\t * This is safe to call multiple times across multiple TaskSubscriptions.\n\t */\n\tpublic volunteer() {\n\t\tif (!this.subscribed) {\n\t\t\t// AgentScheduler throws if the same task is picked twice but we don't care because our\n\t\t\t// worker does nothing. We only care that the AgentScheduler is trying to pick.\n\t\t\t// We also don't care if we throw due to failing the interactive check, because then we'll\n\t\t\t// just appear to never get the task.\n\t\t\tthis.agentScheduler.pick(this.taskId, async () => {}).catch(() => {});\n\t\t\tthis.subscribed = true;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"taskSubscription.js","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAiE;AAcjE;;;;GAIG;AACH,MAAa,gBAAiB,SAAQ,gCAA0C;IAG/E;;;OAGG;IACH,YACkB,cAA+B,EAChC,MAAc;QAE9B,KAAK,EAAE,CAAC;QAHS,mBAAc,GAAd,cAAc,CAAiB;QAChC,WAAM,GAAN,MAAM,CAAQ;QARvB,eAAU,GAAY,KAAK,CAAC;QAWnC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAe,EAAE,EAAE;YAC/C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,CAAC;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,OAAe,EAAE,EAAE;YACjD,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAe,EAAE,EAAE;YAC7C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,OAAO,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACtB,uFAAuF;YACvF,gFAAgF;YAChF,0FAA0F;YAC1F,qCAAqC;YACrC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACxB,CAAC;IACF,CAAC;CACD;AAnDD,4CAmDC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { IEvent } from \"@fluidframework/core-interfaces\";\n\nimport { IAgentScheduler } from \"./agent.js\";\n\n/**\n * Events emitted by {@link TaskSubscription}.\n * @legacy\n * @alpha\n */\nexport interface ITaskSubscriptionEvents extends IEvent {\n\t(event: \"gotTask\" | \"lostTask\", listener: () => void);\n}\n\n/**\n * TaskSubscription works with an AgentScheduler to make it easier to monitor a specific task ownership.\n * @legacy\n * @alpha\n */\nexport class TaskSubscription extends TypedEventEmitter<ITaskSubscriptionEvents> {\n\tprivate subscribed: boolean = false;\n\n\t/**\n\t * @param agentScheduler - The AgentScheduler that will be subscribed against\n\t * @param taskId - The string ID of the task to subscribe against\n\t */\n\tconstructor(\n\t\tprivate readonly agentScheduler: IAgentScheduler,\n\t\tpublic readonly taskId: string,\n\t) {\n\t\tsuper();\n\t\tagentScheduler.on(\"picked\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"gotTask\");\n\t\t\t}\n\t\t});\n\t\tagentScheduler.on(\"released\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"lostTask\");\n\t\t\t}\n\t\t});\n\t\tagentScheduler.on(\"lost\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"lostTask\");\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Check if currently holding ownership of the task.\n\t * @returns true if currently the task owner, false otherwise.\n\t */\n\tpublic haveTask(): boolean {\n\t\treturn this.agentScheduler.pickedTasks().includes(this.taskId);\n\t}\n\n\t/**\n\t * Volunteer for the task. By default, the TaskSubscription will only watch the task and not volunteer.\n\t * This is safe to call multiple times across multiple TaskSubscriptions.\n\t */\n\tpublic volunteer(): void {\n\t\tif (!this.subscribed) {\n\t\t\t// AgentScheduler throws if the same task is picked twice but we don't care because our\n\t\t\t// worker does nothing. We only care that the AgentScheduler is trying to pick.\n\t\t\t// We also don't care if we throw due to failing the interactive check, because then we'll\n\t\t\t// just appear to never get the task.\n\t\t\tthis.agentScheduler.pick(this.taskId, async () => {}).catch(() => {});\n\t\t\tthis.subscribed = true;\n\t\t}\n\t}\n}\n"]}
|
package/lib/scheduler.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
6
|
-
import { IFluidHandle } from "@fluidframework/core-interfaces";
|
|
6
|
+
import type { IFluidHandle, IFluidLoadable } from "@fluidframework/core-interfaces";
|
|
7
7
|
import { FluidDataStoreRuntime } from "@fluidframework/datastore/internal";
|
|
8
8
|
import { IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions/internal";
|
|
9
9
|
import { ConsensusRegisterCollection } from "@fluidframework/register-collection/internal";
|
|
@@ -13,9 +13,9 @@ export declare class AgentScheduler extends TypedEventEmitter<IAgentSchedulerEve
|
|
|
13
13
|
private readonly runtime;
|
|
14
14
|
private readonly context;
|
|
15
15
|
private readonly consensusRegisterCollection;
|
|
16
|
-
static load(runtime: IFluidDataStoreRuntime, context: IFluidDataStoreContext, existing: boolean): Promise<
|
|
17
|
-
get IAgentScheduler():
|
|
18
|
-
get IFluidLoadable():
|
|
16
|
+
static load(runtime: IFluidDataStoreRuntime, context: IFluidDataStoreContext, existing: boolean): Promise<IAgentScheduler>;
|
|
17
|
+
get IAgentScheduler(): IAgentScheduler;
|
|
18
|
+
get IFluidLoadable(): IFluidLoadable;
|
|
19
19
|
private readonly logger;
|
|
20
20
|
private get clientId();
|
|
21
21
|
private readonly registeredTasks;
|
|
@@ -48,7 +48,7 @@ export declare class AgentScheduler extends TypedEventEmitter<IAgentSchedulerEve
|
|
|
48
48
|
export declare class AgentSchedulerFactory implements IFluidDataStoreFactory {
|
|
49
49
|
static readonly type = "_scheduler";
|
|
50
50
|
readonly type = "_scheduler";
|
|
51
|
-
get IFluidDataStoreFactory():
|
|
51
|
+
get IFluidDataStoreFactory(): AgentSchedulerFactory;
|
|
52
52
|
static get registryEntry(): NamedFluidDataStoreRegistryEntry;
|
|
53
53
|
static createChildInstance(parentContext: IFluidDataStoreContext): Promise<IAgentScheduler>;
|
|
54
54
|
instantiateDataStore(context: IFluidDataStoreContext, existing: boolean): Promise<FluidDataStoreRuntime>;
|
package/lib/scheduler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,KAAK,EAEX,YAAY,EACZ,cAAc,EAGd,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACN,qBAAqB,EAGrB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAEN,sBAAsB,EACtB,MAAM,gDAAgD,CAAC;AAExD,OAAO,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,EACN,sBAAsB,EACtB,sBAAsB,EACtB,gCAAgC,EAChC,MAAM,8CAA8C,CAAC;AAStD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AA4BpE,qBAAa,cACZ,SAAQ,iBAAiB,CAAC,qBAAqB,CAC/C,YAAW,eAAe;IAmEzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,2BAA2B;WAnEzB,IAAI,CACvB,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,eAAe,CAAC;IAyB3B,IAAW,eAAe,IAAI,eAAe,CAE5C;IACD,IAAW,cAAc,IAAI,cAAc,CAE1C;IAED,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAE7C,OAAO,KAAK,QAAQ,GAOnB;IAMD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IAKrD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA0C;IAI/E,OAAO,CAAC,YAAY,CAAqB;IAEzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAG3B,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,EAC/B,2BAA2B,EAAE,2BAA2B,CAAC,MAAM,GAAG,IAAI,CAAC;IASzF,IAAW,MAAM,IAAI,YAAY,CAAC,IAAI,CAAC,CAEtC;IAEY,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBjE,OAAO,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BnD,WAAW,IAAI,MAAM,EAAE;YAIhB,YAAY;YAkBZ,WAAW;YAYX,UAAU;IASxB,OAAO,CAAC,eAAe;YAIT,SAAS;IAIvB,OAAO,CAAC,UAAU;IA+ElB,OAAO,CAAC,iBAAiB;YAcX,gBAAgB;IAwB9B,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,cAAc;CAGtB;AA2BD;;;GAGG;AACH,qBAAa,qBAAsB,YAAW,sBAAsB;IACnE,gBAAuB,IAAI,gBAAgB;IAC3C,SAAgB,IAAI,gBAA8B;IAElD,IAAW,sBAAsB,IAAI,qBAAqB,CAEzD;IAED,WAAkB,aAAa,IAAI,gCAAgC,CAElE;WAEmB,mBAAmB,CACtC,aAAa,EAAE,sBAAsB,GACnC,OAAO,CAAC,eAAe,CAAC;IAcd,oBAAoB,CAChC,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,OAAO,GACf,OAAO,CAAC,qBAAqB,CAAC;CASjC"}
|
package/lib/scheduler.js
CHANGED
|
@@ -36,19 +36,20 @@ export class AgentScheduler extends TypedEventEmitter {
|
|
|
36
36
|
static async load(runtime, context, existing) {
|
|
37
37
|
let root;
|
|
38
38
|
let consensusRegisterCollection;
|
|
39
|
-
if (
|
|
39
|
+
if (existing) {
|
|
40
|
+
root = (await runtime.getChannel("root"));
|
|
41
|
+
const handle = await mapWait(root, schedulerId);
|
|
42
|
+
assert(handle !== undefined, 0x116 /* "Missing handle on scheduler load" */);
|
|
43
|
+
consensusRegisterCollection = await handle.get();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
40
46
|
root = SharedMap.create(runtime, "root");
|
|
41
47
|
root.bindToContext();
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
42
49
|
consensusRegisterCollection = ConsensusRegisterCollection.create(runtime);
|
|
43
50
|
consensusRegisterCollection.bindToContext();
|
|
44
51
|
root.set(schedulerId, consensusRegisterCollection.handle);
|
|
45
52
|
}
|
|
46
|
-
else {
|
|
47
|
-
root = (await runtime.getChannel("root"));
|
|
48
|
-
const handle = await mapWait(root, schedulerId);
|
|
49
|
-
assert(handle !== undefined, 0x116 /* "Missing handle on scheduler load" */);
|
|
50
|
-
consensusRegisterCollection = await handle.get();
|
|
51
|
-
}
|
|
52
53
|
const agentScheduler = new AgentScheduler(runtime, context, consensusRegisterCollection);
|
|
53
54
|
agentScheduler.initialize();
|
|
54
55
|
return agentScheduler;
|
|
@@ -152,8 +153,9 @@ export class AgentScheduler extends TypedEventEmitter {
|
|
|
152
153
|
return this.releaseCore([...taskUrls]);
|
|
153
154
|
}
|
|
154
155
|
pickedTasks() {
|
|
155
|
-
return
|
|
156
|
+
return [...this.runningTasks.values()];
|
|
156
157
|
}
|
|
158
|
+
/* eslint-disable unicorn/no-null */
|
|
157
159
|
async registerCore(taskUrls) {
|
|
158
160
|
if (taskUrls.length > 0) {
|
|
159
161
|
const registersP = [];
|
|
@@ -304,6 +306,7 @@ export class AgentScheduler extends TypedEventEmitter {
|
|
|
304
306
|
}
|
|
305
307
|
}
|
|
306
308
|
}
|
|
309
|
+
/* eslint-enable unicorn/no-null */
|
|
307
310
|
isActive() {
|
|
308
311
|
// Scheduler should be active in detached container.
|
|
309
312
|
if (this.runtime.attachState === AttachState.Detached) {
|
|
@@ -359,12 +362,10 @@ class AgentSchedulerRuntime extends FluidDataStoreRuntime {
|
|
|
359
362
|
}
|
|
360
363
|
async request(request) {
|
|
361
364
|
const response = await super.request(request);
|
|
362
|
-
if (response.status === 404) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
return { status: 200, mimeType: "fluid/object", value: agentScheduler };
|
|
367
|
-
}
|
|
365
|
+
if (response.status === 404 && (request.url === "" || request.url === "/")) {
|
|
366
|
+
const agentScheduler = await this.entryPoint.get();
|
|
367
|
+
assert(agentScheduler !== undefined, 0x466 /* entryPoint for AgentSchedulerRuntime should have been initialized by now */);
|
|
368
|
+
return { status: 200, mimeType: "fluid/object", value: agentScheduler };
|
|
368
369
|
}
|
|
369
370
|
return response;
|
|
370
371
|
}
|
package/lib/scheduler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { FluidObject, IFluidHandle, IRequest } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tFluidDataStoreRuntime,\n\tFluidObjectHandle,\n\tISharedObjectRegistry,\n} from \"@fluidframework/datastore/internal\";\nimport {\n\tIChannelFactory,\n\tIFluidDataStoreRuntime,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { ISharedMap, IValueChanged, SharedMap } from \"@fluidframework/map/internal\";\nimport { ConsensusRegisterCollection } from \"@fluidframework/register-collection/internal\";\nimport {\n\tIFluidDataStoreContext,\n\tIFluidDataStoreFactory,\n\tNamedFluidDataStoreRegistryEntry,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tUsageError,\n\tcreateChildLogger,\n\ttagCodeArtifacts,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { IAgentScheduler, IAgentSchedulerEvents } from \"./agent.js\";\n\n// Note: making sure this ID is unique and does not collide with storage provided clientID\nconst UnattachedClientId = `${uuid()}_unattached`;\n\nconst mapWait = async <T = any>(map: ISharedMap, key: string): Promise<T> => {\n\tconst maybeValue = map.get<T>(key);\n\tif (maybeValue !== undefined) {\n\t\treturn maybeValue;\n\t}\n\n\treturn new Promise((resolve) => {\n\t\tconst handler = (changed: IValueChanged) => {\n\t\t\tif (changed.key === key) {\n\t\t\t\tmap.off(\"valueChanged\", handler);\n\t\t\t\tconst value = map.get<T>(changed.key);\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\tthrow new Error(\"Unexpected valueChanged result\");\n\t\t\t\t}\n\t\t\t\tresolve(value);\n\t\t\t}\n\t\t};\n\t\tmap.on(\"valueChanged\", handler);\n\t});\n};\n\nconst schedulerId = \"scheduler\";\n\nexport class AgentScheduler\n\textends TypedEventEmitter<IAgentSchedulerEvents>\n\timplements IAgentScheduler\n{\n\tpublic static async load(\n\t\truntime: IFluidDataStoreRuntime,\n\t\tcontext: IFluidDataStoreContext,\n\t\texisting: boolean,\n\t) {\n\t\tlet root: ISharedMap;\n\t\tlet consensusRegisterCollection: ConsensusRegisterCollection<string | null>;\n\t\tif (!existing) {\n\t\t\troot = SharedMap.create(runtime, \"root\");\n\t\t\troot.bindToContext();\n\t\t\tconsensusRegisterCollection = ConsensusRegisterCollection.create(runtime);\n\t\t\tconsensusRegisterCollection.bindToContext();\n\t\t\troot.set(schedulerId, consensusRegisterCollection.handle);\n\t\t} else {\n\t\t\troot = (await runtime.getChannel(\"root\")) as ISharedMap;\n\t\t\tconst handle = await mapWait<IFluidHandle<ConsensusRegisterCollection<string | null>>>(\n\t\t\t\troot,\n\t\t\t\tschedulerId,\n\t\t\t);\n\t\t\tassert(handle !== undefined, 0x116 /* \"Missing handle on scheduler load\" */);\n\t\t\tconsensusRegisterCollection = await handle.get();\n\t\t}\n\t\tconst agentScheduler = new AgentScheduler(runtime, context, consensusRegisterCollection);\n\t\tagentScheduler.initialize();\n\n\t\treturn agentScheduler;\n\t}\n\n\tpublic get IAgentScheduler() {\n\t\treturn this;\n\t}\n\tpublic get IFluidLoadable() {\n\t\treturn this;\n\t}\n\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tprivate get clientId(): string {\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\treturn UnattachedClientId;\n\t\t}\n\t\tconst clientId = this.runtime.clientId;\n\t\tassert(!!clientId, 0x117 /* \"Trying to get missing clientId!\" */);\n\t\treturn clientId;\n\t}\n\n\t// Set of tasks registered by this client.\n\t// Has no relationship with lists below.\n\t// The only requirement here - a task can be registered by a client only once.\n\t// Other clients can pick these tasks.\n\tprivate readonly registeredTasks = new Set<string>();\n\n\t// List of all tasks client is capable of running (essentially expressed desire to run)\n\t// Client will proactively attempt to pick them up these tasks if they are not assigned to other clients.\n\t// This is a strict superset of tasks running in the client.\n\tprivate readonly locallyRunnableTasks = new Map<string, () => Promise<void>>();\n\n\t// Set of registered tasks client is currently running.\n\t// It's subset of this.locallyRunnableTasks\n\tprivate runningTasks = new Set<string>();\n\n\tprivate readonly _handle: IFluidHandle<this>;\n\n\tconstructor(\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\t\tprivate readonly context: IFluidDataStoreContext,\n\t\tprivate readonly consensusRegisterCollection: ConsensusRegisterCollection<string | null>,\n\t) {\n\t\tsuper();\n\t\tthis.logger = createChildLogger({ logger: runtime.logger });\n\t\t// We are expecting this class to have many listeners, so we suppress noisy \"MaxListenersExceededWarning\" logging.\n\t\tsuper.setMaxListeners(0);\n\t\tthis._handle = new FluidObjectHandle(this, \"\", this.runtime.objectsRoutingContext);\n\t}\n\n\tpublic get handle() {\n\t\treturn this._handle;\n\t}\n\n\tpublic async register(...taskUrls: string[]): Promise<void> {\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tif (this.registeredTasks.has(taskUrl)) {\n\t\t\t\tthrow new UsageError(`Task is already registered`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t}\n\t\tconst unregisteredTasks: string[] = [];\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tthis.registeredTasks.add(taskUrl);\n\t\t\t// Only register for a new task.\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient === undefined) {\n\t\t\t\tunregisteredTasks.push(taskUrl);\n\t\t\t}\n\t\t}\n\t\treturn this.registerCore(unregisteredTasks);\n\t}\n\n\tpublic async pick(taskUrl: string, worker: () => Promise<void>): Promise<void> {\n\t\tif (this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\tthrow new UsageError(`Task is already attempted`, tagCodeArtifacts({ taskUrl }));\n\t\t}\n\t\tthis.locallyRunnableTasks.set(taskUrl, worker);\n\n\t\t// We have a policy to disallow non-interactive clients from taking tasks. Callers of pick() can\n\t\t// either perform this check proactively and call conditionally, or catch the error (in which case\n\t\t// they can know they will not get the task).\n\t\tassert(\n\t\t\tthis.context.deltaManager.clientDetails.capabilities.interactive,\n\t\t\t0x118 /* \"Bad client interactive check\" */,\n\t\t);\n\n\t\t// Check the current status and express interest if it's a new one (undefined) or currently unpicked (null).\n\t\tif (this.isActive()) {\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient === undefined || currentClient === null) {\n\t\t\t\tawait this.writeCore(taskUrl, this.clientId);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async release(...taskUrls: string[]): Promise<void> {\n\t\tconst active = this.isActive();\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tif (!this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\t\tthrow new UsageError(`Task was never registered`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t\tif (!this.runningTasks.has(taskUrl)) {\n\t\t\t\t// If we got disconnected (and are attached), tasks that we WERE picked for at the time of disconnect\n\t\t\t\t// will still show us as holding the task according to getTaskClientId (the CRC is stale), but we\n\t\t\t\t// should not try to release because our disconnect will already result in either someone else or\n\t\t\t\t// ourselves clearing the task upon reconnect.\n\t\t\t\t// This UsageError is to enforce that the caller should check AgentScheduler.pickedTasks before trying\n\t\t\t\t// to release a task.\n\t\t\t\tthrow new UsageError(`Task is not currently picked`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t\t// We may only release tasks that we KNOW we hold (detached state or connected and own the CRC). If we're\n\t\t\t// attached+disconnected then we'll lose the task automatically, and so may not release manually (someone\n\t\t\t// else might hold it by the time we reconnect)\n\t\t\tassert(active, 0x119 /* \"This agent became inactive while releasing\" */);\n\t\t\tif (this.getTaskClientId(taskUrl) !== this.clientId) {\n\t\t\t\tthrow new UsageError(`Task was never picked`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t}\n\t\treturn this.releaseCore([...taskUrls]);\n\t}\n\n\tpublic pickedTasks(): string[] {\n\t\treturn Array.from(this.runningTasks.values());\n\t}\n\n\tprivate async registerCore(taskUrls: string[]): Promise<void> {\n\t\tif (taskUrls.length > 0) {\n\t\t\tconst registersP: Promise<void>[] = [];\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\tregistersP.push(this.writeCore(taskUrl, null));\n\t\t\t}\n\t\t\tawait Promise.all(registersP);\n\n\t\t\t// The registers should have up to date results now. Check the status.\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\tconst taskStatus = this.getTaskClientId(taskUrl);\n\n\t\t\t\t// Task should be either registered (null) or picked up.\n\t\t\t\tassert(taskStatus !== undefined, 0x11a /* `Unsuccessful registration` */);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async releaseCore(taskUrls: string[]) {\n\t\tif (taskUrls.length > 0) {\n\t\t\tconst releasesP: Promise<void>[] = [];\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\t// Remove from local map so that it can be picked later.\n\t\t\t\tthis.locallyRunnableTasks.delete(taskUrl);\n\t\t\t\treleasesP.push(this.writeCore(taskUrl, null));\n\t\t\t}\n\t\t\tawait Promise.all(releasesP);\n\t\t}\n\t}\n\n\tprivate async clearTasks(taskUrls: string[]) {\n\t\tassert(this.isActive(), 0x11b /* \"Trying to clear tasks on inactive agent\" */);\n\t\tconst clearP: Promise<void>[] = [];\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tclearP.push(this.writeCore(taskUrl, null));\n\t\t}\n\t\tawait Promise.all(clearP);\n\t}\n\n\tprivate getTaskClientId(url: string): string | null | undefined {\n\t\treturn this.consensusRegisterCollection.read(url);\n\t}\n\n\tprivate async writeCore(key: string, clientId: string | null): Promise<void> {\n\t\tawait this.consensusRegisterCollection.write(key, clientId);\n\t}\n\n\tprivate initialize() {\n\t\tconst quorum = this.runtime.getQuorum();\n\t\t// A client left the quorum. Iterate and clear tasks held by that client.\n\t\t// Ideally a leader should do this cleanup. But it's complicated when a leader itself leaves.\n\t\t// Probably okay for now to have every client try to do this.\n\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\tquorum.on(\"removeMember\", async (clientId: string) => {\n\t\t\t// TODO AB#19980: The scenario with a detached routing context is not fully supported.\n\t\t\tif (!this.runtime.objectsRoutingContext.isAttached) return;\n\t\t\t// Cleanup only if connected. If not, cleanup will happen in initializeCore() that runs on connection.\n\t\t\tif (this.isActive()) {\n\t\t\t\tconst tasks: Promise<any>[] = [];\n\t\t\t\tconst leftTasks: string[] = [];\n\t\t\t\tfor (const taskUrl of this.consensusRegisterCollection.keys()) {\n\t\t\t\t\tif (this.getTaskClientId(taskUrl) === clientId) {\n\t\t\t\t\t\tif (this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\t\t\t\t\ttasks.push(this.writeCore(taskUrl, this.clientId));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tleftTasks.push(taskUrl);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttasks.push(this.clearTasks(leftTasks));\n\t\t\t\tawait Promise.all(tasks).catch((error) => {\n\t\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_RemoveMemberError\", error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t// Listeners for new/released tasks. All clients will try to grab at the same time.\n\t\t// May be we want a randomized timer (Something like raft) to reduce chattiness?\n\t\tthis.consensusRegisterCollection.on(\n\t\t\t\"atomicChanged\",\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\t\tasync (key: string, currentClient: string | null) => {\n\t\t\t\t// Check if this client was chosen.\n\t\t\t\tif (this.isActive() && currentClient === this.clientId) {\n\t\t\t\t\tthis.onNewTaskAssigned(key);\n\t\t\t\t} else {\n\t\t\t\t\t// The call below mutates the consensusRegisterCollection in\n\t\t\t\t\t// its event handler, which is not safe.\n\t\t\t\t\t// We need to force this to be part of a different batch of ops by\n\t\t\t\t\t// scheduling a microtask in order to work around the current validations.\n\t\t\t\t\t// This is not recommended and should be avoided.\n\t\t\t\t\tawait Promise.resolve().then(async () => {\n\t\t\t\t\t\tawait this.onTaskReassigned(key, currentClient);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (this.isActive()) {\n\t\t\tthis.initializeCore();\n\t\t}\n\n\t\tthis.runtime.on(\"connected\", () => {\n\t\t\tif (this.isActive()) {\n\t\t\t\tthis.initializeCore();\n\t\t\t}\n\t\t});\n\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\tthis.runtime\n\t\t\t\t.waitAttached()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.clearRunningTasks();\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_clearRunningTasks\", error);\n\t\t\t\t});\n\t\t}\n\n\t\tthis.runtime.on(\"disconnected\", () => {\n\t\t\tif (this.runtime.attachState !== AttachState.Detached) {\n\t\t\t\tthis.clearRunningTasks();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate onNewTaskAssigned(key: string) {\n\t\tassert(!this.runningTasks.has(key), 0x11d /* \"task is already running\" */);\n\t\tthis.runningTasks.add(key);\n\t\tconst worker = this.locallyRunnableTasks.get(key);\n\t\tif (worker === undefined) {\n\t\t\tthis.sendErrorEvent(\"AgentScheduler_UnwantedChange\", undefined, key);\n\t\t} else {\n\t\t\tthis.emit(\"picked\", key);\n\t\t\tworker().catch((error) => {\n\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_FailedWork\", error, key);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async onTaskReassigned(key: string, currentClient: string | null) {\n\t\tif (this.runningTasks.has(key)) {\n\t\t\tthis.runningTasks.delete(key);\n\t\t\tthis.emit(\"released\", key);\n\t\t}\n\t\tassert(currentClient !== undefined, 0x11e /* \"client is undefined\" */);\n\t\tif (this.isActive()) {\n\t\t\t// attempt to pick up task if we are connected.\n\t\t\t// If not, initializeCore() will do it when connected\n\t\t\tif (currentClient === null) {\n\t\t\t\tif (this.locallyRunnableTasks.has(key)) {\n\t\t\t\t\tawait this.writeCore(key, this.clientId);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Check if the op came from dropped client\n\t\t\t// This could happen when \"old\" ops are submitted on reconnection.\n\t\t\t// They carry \"old\" ref seq number, but if write is not contested, it will get accepted\n\t\t\telse if (this.runtime.getQuorum().getMember(currentClient) === undefined) {\n\t\t\t\tawait this.writeCore(key, null);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isActive() {\n\t\t// Scheduler should be active in detached container.\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!this.runtime.connected) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note: we are not checking for this.context.deltaManager.clientDetails.capabilities.interactive\n\t\t// here. Instead we assert in pick() if a non-interactive client tries to pick.\n\n\t\treturn this.context.deltaManager.active;\n\t}\n\n\tprivate initializeCore() {\n\t\t// Nobody released the tasks held by last client in previous session.\n\t\t// Check to see if this client needs to do this.\n\t\tconst clearCandidates: string[] = [];\n\t\tconst tasks: Promise<any>[] = [];\n\n\t\tfor (const [taskUrl] of this.locallyRunnableTasks) {\n\t\t\tif (!this.getTaskClientId(taskUrl)) {\n\t\t\t\ttasks.push(this.writeCore(taskUrl, this.clientId));\n\t\t\t}\n\t\t}\n\n\t\tfor (const taskUrl of this.consensusRegisterCollection.keys()) {\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient && this.runtime.getQuorum().getMember(currentClient) === undefined) {\n\t\t\t\tclearCandidates.push(taskUrl);\n\t\t\t}\n\t\t}\n\n\t\ttasks.push(this.clearTasks(clearCandidates));\n\n\t\tPromise.all(tasks).catch((error) => {\n\t\t\tthis.sendErrorEvent(\"AgentScheduler_InitError\", error);\n\t\t});\n\t}\n\n\tprivate clearRunningTasks() {\n\t\tconst tasks = this.runningTasks;\n\t\tthis.runningTasks = new Set<string>();\n\n\t\tif (this.isActive()) {\n\t\t\t// Clear all tasks with UnattachedClientId (if was unattached) and reapply for tasks with new clientId\n\t\t\t// If we are simply disconnected, then proper cleanup will be done on connection.\n\t\t\tthis.initializeCore();\n\t\t}\n\n\t\tfor (const task of tasks) {\n\t\t\tthis.emit(\"lost\", task);\n\t\t}\n\t}\n\n\tprivate sendErrorEvent(eventName: string, error: any, key?: string) {\n\t\tthis.logger.sendErrorEvent({ eventName, key }, error);\n\t}\n}\n\nclass AgentSchedulerRuntime extends FluidDataStoreRuntime {\n\tconstructor(\n\t\tdataStoreContext: IFluidDataStoreContext,\n\t\tsharedObjectRegistry: ISharedObjectRegistry,\n\t\texisting: boolean,\n\t) {\n\t\tsuper(dataStoreContext, sharedObjectRegistry, existing, async () =>\n\t\t\tAgentScheduler.load(this, dataStoreContext, existing),\n\t\t);\n\t}\n\tpublic async request(request: IRequest) {\n\t\tconst response = await super.request(request);\n\t\tif (response.status === 404) {\n\t\t\tif (request.url === \"\" || request.url === \"/\") {\n\t\t\t\tconst agentScheduler = await this.entryPoint.get();\n\t\t\t\tassert(\n\t\t\t\t\tagentScheduler !== undefined,\n\t\t\t\t\t0x466 /* entryPoint for AgentSchedulerRuntime should have been initialized by now */,\n\t\t\t\t);\n\n\t\t\t\treturn { status: 200, mimeType: \"fluid/object\", value: agentScheduler };\n\t\t\t}\n\t\t}\n\t\treturn response;\n\t}\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport class AgentSchedulerFactory implements IFluidDataStoreFactory {\n\tpublic static readonly type = \"_scheduler\";\n\tpublic readonly type = AgentSchedulerFactory.type;\n\n\tpublic get IFluidDataStoreFactory() {\n\t\treturn this;\n\t}\n\n\tpublic static get registryEntry(): NamedFluidDataStoreRegistryEntry {\n\t\treturn [this.type, Promise.resolve(new AgentSchedulerFactory())];\n\t}\n\n\tpublic static async createChildInstance(\n\t\tparentContext: IFluidDataStoreContext,\n\t): Promise<IAgentScheduler> {\n\t\tconst packagePath = [...parentContext.packagePath, AgentSchedulerFactory.type];\n\t\tconst dataStore = await parentContext.containerRuntime.createDataStore(packagePath);\n\t\tconst entryPoint: FluidObject<IAgentScheduler> = await dataStore.entryPoint.get();\n\n\t\t// AgentSchedulerRuntime always puts an AgentScheduler object in the data store's entryPoint, but double-check\n\t\t// while we plumb entryPoints correctly everywhere, so we can be sure the cast below is fine.\n\t\tassert(\n\t\t\tentryPoint.IAgentScheduler !== undefined,\n\t\t\t0x467 /* The data store's entryPoint is not an AgentScheduler! */,\n\t\t);\n\t\treturn entryPoint as unknown as AgentScheduler;\n\t}\n\n\tpublic async instantiateDataStore(\n\t\tcontext: IFluidDataStoreContext,\n\t\texisting: boolean,\n\t): Promise<FluidDataStoreRuntime> {\n\t\tconst mapFactory = SharedMap.getFactory();\n\t\tconst consensusRegisterCollectionFactory = ConsensusRegisterCollection.getFactory();\n\t\tconst dataTypes = new Map<string, IChannelFactory>();\n\t\tdataTypes.set(mapFactory.type, mapFactory);\n\t\tdataTypes.set(consensusRegisterCollectionFactory.type, consensusRegisterCollectionFactory);\n\n\t\treturn new AgentSchedulerRuntime(context, dataTypes, existing);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.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 { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport type {\n\tFluidObject,\n\tIFluidHandle,\n\tIFluidLoadable,\n\tIRequest,\n\tIResponse,\n} from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport {\n\tFluidDataStoreRuntime,\n\tFluidObjectHandle,\n\tISharedObjectRegistry,\n} from \"@fluidframework/datastore/internal\";\nimport {\n\tIChannelFactory,\n\tIFluidDataStoreRuntime,\n} from \"@fluidframework/datastore-definitions/internal\";\nimport { ISharedMap, IValueChanged, SharedMap } from \"@fluidframework/map/internal\";\nimport { ConsensusRegisterCollection } from \"@fluidframework/register-collection/internal\";\nimport {\n\tIFluidDataStoreContext,\n\tIFluidDataStoreFactory,\n\tNamedFluidDataStoreRegistryEntry,\n} from \"@fluidframework/runtime-definitions/internal\";\nimport {\n\ttype ITelemetryLoggerExt,\n\tUsageError,\n\tcreateChildLogger,\n\ttagCodeArtifacts,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { IAgentScheduler, IAgentSchedulerEvents } from \"./agent.js\";\n\n// Note: making sure this ID is unique and does not collide with storage provided clientID\nconst UnattachedClientId = `${uuid()}_unattached`;\n\nconst mapWait = async <T = unknown>(map: ISharedMap, key: string): Promise<T> => {\n\tconst maybeValue = map.get<T>(key);\n\tif (maybeValue !== undefined) {\n\t\treturn maybeValue;\n\t}\n\n\treturn new Promise((resolve) => {\n\t\tconst handler = (changed: IValueChanged): void => {\n\t\t\tif (changed.key === key) {\n\t\t\t\tmap.off(\"valueChanged\", handler);\n\t\t\t\tconst value = map.get<T>(changed.key);\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\tthrow new Error(\"Unexpected valueChanged result\");\n\t\t\t\t}\n\t\t\t\tresolve(value);\n\t\t\t}\n\t\t};\n\t\tmap.on(\"valueChanged\", handler);\n\t});\n};\n\nconst schedulerId = \"scheduler\";\n\nexport class AgentScheduler\n\textends TypedEventEmitter<IAgentSchedulerEvents>\n\timplements IAgentScheduler\n{\n\tpublic static async load(\n\t\truntime: IFluidDataStoreRuntime,\n\t\tcontext: IFluidDataStoreContext,\n\t\texisting: boolean,\n\t): Promise<IAgentScheduler> {\n\t\tlet root: ISharedMap;\n\t\tlet consensusRegisterCollection: ConsensusRegisterCollection<string | null>;\n\t\tif (existing) {\n\t\t\troot = (await runtime.getChannel(\"root\")) as ISharedMap;\n\t\t\tconst handle = await mapWait<IFluidHandle<ConsensusRegisterCollection<string | null>>>(\n\t\t\t\troot,\n\t\t\t\tschedulerId,\n\t\t\t);\n\t\t\tassert(handle !== undefined, 0x116 /* \"Missing handle on scheduler load\" */);\n\t\t\tconsensusRegisterCollection = await handle.get();\n\t\t} else {\n\t\t\troot = SharedMap.create(runtime, \"root\");\n\t\t\troot.bindToContext();\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconsensusRegisterCollection = ConsensusRegisterCollection.create(runtime);\n\t\t\tconsensusRegisterCollection.bindToContext();\n\t\t\troot.set(schedulerId, consensusRegisterCollection.handle);\n\t\t}\n\t\tconst agentScheduler = new AgentScheduler(runtime, context, consensusRegisterCollection);\n\t\tagentScheduler.initialize();\n\n\t\treturn agentScheduler;\n\t}\n\n\tpublic get IAgentScheduler(): IAgentScheduler {\n\t\treturn this;\n\t}\n\tpublic get IFluidLoadable(): IFluidLoadable {\n\t\treturn this;\n\t}\n\n\tprivate readonly logger: ITelemetryLoggerExt;\n\n\tprivate get clientId(): string {\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\treturn UnattachedClientId;\n\t\t}\n\t\tconst clientId = this.runtime.clientId;\n\t\tassert(!!clientId, 0x117 /* \"Trying to get missing clientId!\" */);\n\t\treturn clientId;\n\t}\n\n\t// Set of tasks registered by this client.\n\t// Has no relationship with lists below.\n\t// The only requirement here - a task can be registered by a client only once.\n\t// Other clients can pick these tasks.\n\tprivate readonly registeredTasks = new Set<string>();\n\n\t// List of all tasks client is capable of running (essentially expressed desire to run)\n\t// Client will proactively attempt to pick them up these tasks if they are not assigned to other clients.\n\t// This is a strict superset of tasks running in the client.\n\tprivate readonly locallyRunnableTasks = new Map<string, () => Promise<void>>();\n\n\t// Set of registered tasks client is currently running.\n\t// It's subset of this.locallyRunnableTasks\n\tprivate runningTasks = new Set<string>();\n\n\tprivate readonly _handle: IFluidHandle<this>;\n\n\tconstructor(\n\t\tprivate readonly runtime: IFluidDataStoreRuntime,\n\t\tprivate readonly context: IFluidDataStoreContext,\n\t\tprivate readonly consensusRegisterCollection: ConsensusRegisterCollection<string | null>,\n\t) {\n\t\tsuper();\n\t\tthis.logger = createChildLogger({ logger: runtime.logger });\n\t\t// We are expecting this class to have many listeners, so we suppress noisy \"MaxListenersExceededWarning\" logging.\n\t\tsuper.setMaxListeners(0);\n\t\tthis._handle = new FluidObjectHandle(this, \"\", this.runtime.objectsRoutingContext);\n\t}\n\n\tpublic get handle(): IFluidHandle<this> {\n\t\treturn this._handle;\n\t}\n\n\tpublic async register(...taskUrls: string[]): Promise<void> {\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tif (this.registeredTasks.has(taskUrl)) {\n\t\t\t\tthrow new UsageError(`Task is already registered`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t}\n\t\tconst unregisteredTasks: string[] = [];\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tthis.registeredTasks.add(taskUrl);\n\t\t\t// Only register for a new task.\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient === undefined) {\n\t\t\t\tunregisteredTasks.push(taskUrl);\n\t\t\t}\n\t\t}\n\t\treturn this.registerCore(unregisteredTasks);\n\t}\n\n\tpublic async pick(taskUrl: string, worker: () => Promise<void>): Promise<void> {\n\t\tif (this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\tthrow new UsageError(`Task is already attempted`, tagCodeArtifacts({ taskUrl }));\n\t\t}\n\t\tthis.locallyRunnableTasks.set(taskUrl, worker);\n\n\t\t// We have a policy to disallow non-interactive clients from taking tasks. Callers of pick() can\n\t\t// either perform this check proactively and call conditionally, or catch the error (in which case\n\t\t// they can know they will not get the task).\n\t\tassert(\n\t\t\tthis.context.deltaManager.clientDetails.capabilities.interactive,\n\t\t\t0x118 /* \"Bad client interactive check\" */,\n\t\t);\n\n\t\t// Check the current status and express interest if it's a new one (undefined) or currently unpicked (null).\n\t\tif (this.isActive()) {\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient === undefined || currentClient === null) {\n\t\t\t\tawait this.writeCore(taskUrl, this.clientId);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async release(...taskUrls: string[]): Promise<void> {\n\t\tconst active = this.isActive();\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tif (!this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\t\tthrow new UsageError(`Task was never registered`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t\tif (!this.runningTasks.has(taskUrl)) {\n\t\t\t\t// If we got disconnected (and are attached), tasks that we WERE picked for at the time of disconnect\n\t\t\t\t// will still show us as holding the task according to getTaskClientId (the CRC is stale), but we\n\t\t\t\t// should not try to release because our disconnect will already result in either someone else or\n\t\t\t\t// ourselves clearing the task upon reconnect.\n\t\t\t\t// This UsageError is to enforce that the caller should check AgentScheduler.pickedTasks before trying\n\t\t\t\t// to release a task.\n\t\t\t\tthrow new UsageError(`Task is not currently picked`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t\t// We may only release tasks that we KNOW we hold (detached state or connected and own the CRC). If we're\n\t\t\t// attached+disconnected then we'll lose the task automatically, and so may not release manually (someone\n\t\t\t// else might hold it by the time we reconnect)\n\t\t\tassert(active, 0x119 /* \"This agent became inactive while releasing\" */);\n\t\t\tif (this.getTaskClientId(taskUrl) !== this.clientId) {\n\t\t\t\tthrow new UsageError(`Task was never picked`, tagCodeArtifacts({ taskUrl }));\n\t\t\t}\n\t\t}\n\t\treturn this.releaseCore([...taskUrls]);\n\t}\n\n\tpublic pickedTasks(): string[] {\n\t\treturn [...this.runningTasks.values()];\n\t}\n\t/* eslint-disable unicorn/no-null */\n\tprivate async registerCore(taskUrls: string[]): Promise<void> {\n\t\tif (taskUrls.length > 0) {\n\t\t\tconst registersP: Promise<void>[] = [];\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\tregistersP.push(this.writeCore(taskUrl, null));\n\t\t\t}\n\t\t\tawait Promise.all(registersP);\n\n\t\t\t// The registers should have up to date results now. Check the status.\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\tconst taskStatus = this.getTaskClientId(taskUrl);\n\n\t\t\t\t// Task should be either registered (null) or picked up.\n\t\t\t\tassert(taskStatus !== undefined, 0x11a /* `Unsuccessful registration` */);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async releaseCore(taskUrls: string[]): Promise<void> {\n\t\tif (taskUrls.length > 0) {\n\t\t\tconst releasesP: Promise<void>[] = [];\n\t\t\tfor (const taskUrl of taskUrls) {\n\t\t\t\t// Remove from local map so that it can be picked later.\n\t\t\t\tthis.locallyRunnableTasks.delete(taskUrl);\n\t\t\t\treleasesP.push(this.writeCore(taskUrl, null));\n\t\t\t}\n\t\t\tawait Promise.all(releasesP);\n\t\t}\n\t}\n\n\tprivate async clearTasks(taskUrls: string[]): Promise<void> {\n\t\tassert(this.isActive(), 0x11b /* \"Trying to clear tasks on inactive agent\" */);\n\t\tconst clearP: Promise<void>[] = [];\n\t\tfor (const taskUrl of taskUrls) {\n\t\t\tclearP.push(this.writeCore(taskUrl, null));\n\t\t}\n\t\tawait Promise.all(clearP);\n\t}\n\n\tprivate getTaskClientId(url: string): string | null | undefined {\n\t\treturn this.consensusRegisterCollection.read(url);\n\t}\n\n\tprivate async writeCore(key: string, clientId: string | null): Promise<void> {\n\t\tawait this.consensusRegisterCollection.write(key, clientId);\n\t}\n\n\tprivate initialize(): void {\n\t\tconst quorum = this.runtime.getQuorum();\n\t\t// A client left the quorum. Iterate and clear tasks held by that client.\n\t\t// Ideally a leader should do this cleanup. But it's complicated when a leader itself leaves.\n\t\t// Probably okay for now to have every client try to do this.\n\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\tquorum.on(\"removeMember\", async (clientId: string) => {\n\t\t\t// TODO AB#19980: The scenario with a detached routing context is not fully supported.\n\t\t\tif (!this.runtime.objectsRoutingContext.isAttached) return;\n\t\t\t// Cleanup only if connected. If not, cleanup will happen in initializeCore() that runs on connection.\n\t\t\tif (this.isActive()) {\n\t\t\t\tconst tasks: Promise<unknown>[] = [];\n\t\t\t\tconst leftTasks: string[] = [];\n\t\t\t\tfor (const taskUrl of this.consensusRegisterCollection.keys()) {\n\t\t\t\t\tif (this.getTaskClientId(taskUrl) === clientId) {\n\t\t\t\t\t\tif (this.locallyRunnableTasks.has(taskUrl)) {\n\t\t\t\t\t\t\ttasks.push(this.writeCore(taskUrl, this.clientId));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tleftTasks.push(taskUrl);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttasks.push(this.clearTasks(leftTasks));\n\t\t\t\tawait Promise.all(tasks).catch((error) => {\n\t\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_RemoveMemberError\", error);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t// Listeners for new/released tasks. All clients will try to grab at the same time.\n\t\t// May be we want a randomized timer (Something like raft) to reduce chattiness?\n\t\tthis.consensusRegisterCollection.on(\n\t\t\t\"atomicChanged\",\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-misused-promises\n\t\t\tasync (key: string, currentClient: string | null) => {\n\t\t\t\t// Check if this client was chosen.\n\t\t\t\tif (this.isActive() && currentClient === this.clientId) {\n\t\t\t\t\tthis.onNewTaskAssigned(key);\n\t\t\t\t} else {\n\t\t\t\t\t// The call below mutates the consensusRegisterCollection in\n\t\t\t\t\t// its event handler, which is not safe.\n\t\t\t\t\t// We need to force this to be part of a different batch of ops by\n\t\t\t\t\t// scheduling a microtask in order to work around the current validations.\n\t\t\t\t\t// This is not recommended and should be avoided.\n\t\t\t\t\tawait Promise.resolve().then(async () => {\n\t\t\t\t\t\tawait this.onTaskReassigned(key, currentClient);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (this.isActive()) {\n\t\t\tthis.initializeCore();\n\t\t}\n\n\t\tthis.runtime.on(\"connected\", () => {\n\t\t\tif (this.isActive()) {\n\t\t\t\tthis.initializeCore();\n\t\t\t}\n\t\t});\n\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\tthis.runtime\n\t\t\t\t.waitAttached()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.clearRunningTasks();\n\t\t\t\t})\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_clearRunningTasks\", error);\n\t\t\t\t});\n\t\t}\n\n\t\tthis.runtime.on(\"disconnected\", () => {\n\t\t\tif (this.runtime.attachState !== AttachState.Detached) {\n\t\t\t\tthis.clearRunningTasks();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate onNewTaskAssigned(key: string): void {\n\t\tassert(!this.runningTasks.has(key), 0x11d /* \"task is already running\" */);\n\t\tthis.runningTasks.add(key);\n\t\tconst worker = this.locallyRunnableTasks.get(key);\n\t\tif (worker === undefined) {\n\t\t\tthis.sendErrorEvent(\"AgentScheduler_UnwantedChange\", undefined, key);\n\t\t} else {\n\t\t\tthis.emit(\"picked\", key);\n\t\t\tworker().catch((error) => {\n\t\t\t\tthis.sendErrorEvent(\"AgentScheduler_FailedWork\", error, key);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async onTaskReassigned(key: string, currentClient: string | null): Promise<void> {\n\t\tif (this.runningTasks.has(key)) {\n\t\t\tthis.runningTasks.delete(key);\n\t\t\tthis.emit(\"released\", key);\n\t\t}\n\t\tassert(currentClient !== undefined, 0x11e /* \"client is undefined\" */);\n\t\tif (this.isActive()) {\n\t\t\t// attempt to pick up task if we are connected.\n\t\t\t// If not, initializeCore() will do it when connected\n\t\t\tif (currentClient === null) {\n\t\t\t\tif (this.locallyRunnableTasks.has(key)) {\n\t\t\t\t\tawait this.writeCore(key, this.clientId);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Check if the op came from dropped client\n\t\t\t// This could happen when \"old\" ops are submitted on reconnection.\n\t\t\t// They carry \"old\" ref seq number, but if write is not contested, it will get accepted\n\t\t\telse if (this.runtime.getQuorum().getMember(currentClient) === undefined) {\n\t\t\t\tawait this.writeCore(key, null);\n\t\t\t}\n\t\t}\n\t}\n\t/* eslint-enable unicorn/no-null */\n\n\tprivate isActive(): boolean {\n\t\t// Scheduler should be active in detached container.\n\t\tif (this.runtime.attachState === AttachState.Detached) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!this.runtime.connected) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note: we are not checking for this.context.deltaManager.clientDetails.capabilities.interactive\n\t\t// here. Instead we assert in pick() if a non-interactive client tries to pick.\n\n\t\treturn this.context.deltaManager.active;\n\t}\n\n\tprivate initializeCore(): void {\n\t\t// Nobody released the tasks held by last client in previous session.\n\t\t// Check to see if this client needs to do this.\n\t\tconst clearCandidates: string[] = [];\n\t\tconst tasks: Promise<unknown>[] = [];\n\n\t\tfor (const [taskUrl] of this.locallyRunnableTasks) {\n\t\t\tif (!this.getTaskClientId(taskUrl)) {\n\t\t\t\ttasks.push(this.writeCore(taskUrl, this.clientId));\n\t\t\t}\n\t\t}\n\n\t\tfor (const taskUrl of this.consensusRegisterCollection.keys()) {\n\t\t\tconst currentClient = this.getTaskClientId(taskUrl);\n\t\t\tif (currentClient && this.runtime.getQuorum().getMember(currentClient) === undefined) {\n\t\t\t\tclearCandidates.push(taskUrl);\n\t\t\t}\n\t\t}\n\n\t\ttasks.push(this.clearTasks(clearCandidates));\n\n\t\tPromise.all(tasks).catch((error) => {\n\t\t\tthis.sendErrorEvent(\"AgentScheduler_InitError\", error);\n\t\t});\n\t}\n\n\tprivate clearRunningTasks(): void {\n\t\tconst tasks = this.runningTasks;\n\t\tthis.runningTasks = new Set<string>();\n\n\t\tif (this.isActive()) {\n\t\t\t// Clear all tasks with UnattachedClientId (if was unattached) and reapply for tasks with new clientId\n\t\t\t// If we are simply disconnected, then proper cleanup will be done on connection.\n\t\t\tthis.initializeCore();\n\t\t}\n\n\t\tfor (const task of tasks) {\n\t\t\tthis.emit(\"lost\", task);\n\t\t}\n\t}\n\n\tprivate sendErrorEvent(eventName: string, error: unknown, key?: string): void {\n\t\tthis.logger.sendErrorEvent({ eventName, key }, error);\n\t}\n}\n\nclass AgentSchedulerRuntime extends FluidDataStoreRuntime {\n\tconstructor(\n\t\tdataStoreContext: IFluidDataStoreContext,\n\t\tsharedObjectRegistry: ISharedObjectRegistry,\n\t\texisting: boolean,\n\t) {\n\t\tsuper(dataStoreContext, sharedObjectRegistry, existing, async () =>\n\t\t\tAgentScheduler.load(this, dataStoreContext, existing),\n\t\t);\n\t}\n\tpublic async request(request: IRequest): Promise<IResponse> {\n\t\tconst response = await super.request(request);\n\t\tif (response.status === 404 && (request.url === \"\" || request.url === \"/\")) {\n\t\t\tconst agentScheduler = await this.entryPoint.get();\n\t\t\tassert(\n\t\t\t\tagentScheduler !== undefined,\n\t\t\t\t0x466 /* entryPoint for AgentSchedulerRuntime should have been initialized by now */,\n\t\t\t);\n\n\t\t\treturn { status: 200, mimeType: \"fluid/object\", value: agentScheduler };\n\t\t}\n\t\treturn response;\n\t}\n}\n\n/**\n * @legacy\n * @alpha\n */\nexport class AgentSchedulerFactory implements IFluidDataStoreFactory {\n\tpublic static readonly type = \"_scheduler\";\n\tpublic readonly type = AgentSchedulerFactory.type;\n\n\tpublic get IFluidDataStoreFactory(): AgentSchedulerFactory {\n\t\treturn this;\n\t}\n\n\tpublic static get registryEntry(): NamedFluidDataStoreRegistryEntry {\n\t\treturn [this.type, Promise.resolve(new AgentSchedulerFactory())];\n\t}\n\n\tpublic static async createChildInstance(\n\t\tparentContext: IFluidDataStoreContext,\n\t): Promise<IAgentScheduler> {\n\t\tconst packagePath = [...parentContext.packagePath, AgentSchedulerFactory.type];\n\t\tconst dataStore = await parentContext.containerRuntime.createDataStore(packagePath);\n\t\tconst entryPoint: FluidObject<IAgentScheduler> = await dataStore.entryPoint.get();\n\n\t\t// AgentSchedulerRuntime always puts an AgentScheduler object in the data store's entryPoint, but double-check\n\t\t// while we plumb entryPoints correctly everywhere, so we can be sure the cast below is fine.\n\t\tassert(\n\t\t\tentryPoint.IAgentScheduler !== undefined,\n\t\t\t0x467 /* The data store's entryPoint is not an AgentScheduler! */,\n\t\t);\n\t\treturn entryPoint as unknown as AgentScheduler;\n\t}\n\n\tpublic async instantiateDataStore(\n\t\tcontext: IFluidDataStoreContext,\n\t\texisting: boolean,\n\t): Promise<FluidDataStoreRuntime> {\n\t\tconst mapFactory = SharedMap.getFactory();\n\t\tconst consensusRegisterCollectionFactory = ConsensusRegisterCollection.getFactory();\n\t\tconst dataTypes = new Map<string, IChannelFactory>();\n\t\tdataTypes.set(mapFactory.type, mapFactory);\n\t\tdataTypes.set(consensusRegisterCollectionFactory.type, consensusRegisterCollectionFactory);\n\n\t\treturn new AgentSchedulerRuntime(context, dataTypes, existing);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taskSubscription.d.ts","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,uBAAwB,SAAQ,MAAM;IACtD,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CACtD;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,iBAAiB,CAAC,uBAAuB,CAAC;IAQ9E,OAAO,CAAC,QAAQ,CAAC,cAAc;aACf,MAAM,EAAE,MAAM;IAR/B,OAAO,CAAC,UAAU,CAAkB;IAEpC;;;OAGG;gBAEe,cAAc,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM;IAoB/B;;;OAGG;IACI,QAAQ;
|
|
1
|
+
{"version":3,"file":"taskSubscription.d.ts","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,uBAAwB,SAAQ,MAAM;IACtD,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CACtD;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,iBAAiB,CAAC,uBAAuB,CAAC;IAQ9E,OAAO,CAAC,QAAQ,CAAC,cAAc;aACf,MAAM,EAAE,MAAM;IAR/B,OAAO,CAAC,UAAU,CAAkB;IAEpC;;;OAGG;gBAEe,cAAc,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM;IAoB/B;;;OAGG;IACI,QAAQ,IAAI,OAAO;IAI1B;;;OAGG;IACI,SAAS,IAAI,IAAI;CAUxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taskSubscription.js","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAcjE;;;;GAIG;AACH,MAAM,OAAO,gBAAiB,SAAQ,iBAA0C;IAG/E;;;OAGG;IACH,YACkB,cAA+B,EAChC,MAAc;QAE9B,KAAK,EAAE,CAAC;QAHS,mBAAc,GAAd,cAAc,CAAiB;QAChC,WAAM,GAAN,MAAM,CAAQ;QARvB,eAAU,GAAY,KAAK,CAAC;QAWnC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAe,EAAE,EAAE;YAC/C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,CAAC;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,OAAe,EAAE,EAAE;YACjD,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAe,EAAE,EAAE;YAC7C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,OAAO,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACtB,uFAAuF;YACvF,gFAAgF;YAChF,0FAA0F;YAC1F,qCAAqC;YACrC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACxB,CAAC;IACF,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { IEvent } from \"@fluidframework/core-interfaces\";\n\nimport { IAgentScheduler } from \"./agent.js\";\n\n/**\n * Events emitted by {@link TaskSubscription}.\n * @legacy\n * @alpha\n */\nexport interface ITaskSubscriptionEvents extends IEvent {\n\t(event: \"gotTask\" | \"lostTask\", listener: () => void);\n}\n\n/**\n * TaskSubscription works with an AgentScheduler to make it easier to monitor a specific task ownership.\n * @legacy\n * @alpha\n */\nexport class TaskSubscription extends TypedEventEmitter<ITaskSubscriptionEvents> {\n\tprivate subscribed: boolean = false;\n\n\t/**\n\t * @param agentScheduler - The AgentScheduler that will be subscribed against\n\t * @param taskId - The string ID of the task to subscribe against\n\t */\n\tconstructor(\n\t\tprivate readonly agentScheduler: IAgentScheduler,\n\t\tpublic readonly taskId: string,\n\t) {\n\t\tsuper();\n\t\tagentScheduler.on(\"picked\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"gotTask\");\n\t\t\t}\n\t\t});\n\t\tagentScheduler.on(\"released\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"lostTask\");\n\t\t\t}\n\t\t});\n\t\tagentScheduler.on(\"lost\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"lostTask\");\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Check if currently holding ownership of the task.\n\t * @returns true if currently the task owner, false otherwise.\n\t */\n\tpublic haveTask() {\n\t\treturn this.agentScheduler.pickedTasks().includes(this.taskId);\n\t}\n\n\t/**\n\t * Volunteer for the task. By default, the TaskSubscription will only watch the task and not volunteer.\n\t * This is safe to call multiple times across multiple TaskSubscriptions.\n\t */\n\tpublic volunteer() {\n\t\tif (!this.subscribed) {\n\t\t\t// AgentScheduler throws if the same task is picked twice but we don't care because our\n\t\t\t// worker does nothing. We only care that the AgentScheduler is trying to pick.\n\t\t\t// We also don't care if we throw due to failing the interactive check, because then we'll\n\t\t\t// just appear to never get the task.\n\t\t\tthis.agentScheduler.pick(this.taskId, async () => {}).catch(() => {});\n\t\t\tthis.subscribed = true;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"taskSubscription.js","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAcjE;;;;GAIG;AACH,MAAM,OAAO,gBAAiB,SAAQ,iBAA0C;IAG/E;;;OAGG;IACH,YACkB,cAA+B,EAChC,MAAc;QAE9B,KAAK,EAAE,CAAC;QAHS,mBAAc,GAAd,cAAc,CAAiB;QAChC,WAAM,GAAN,MAAM,CAAQ;QARvB,eAAU,GAAY,KAAK,CAAC;QAWnC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAe,EAAE,EAAE;YAC/C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,CAAC;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,OAAe,EAAE,EAAE;YACjD,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAe,EAAE,EAAE;YAC7C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACI,QAAQ;QACd,OAAO,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED;;;OAGG;IACI,SAAS;QACf,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACtB,uFAAuF;YACvF,gFAAgF;YAChF,0FAA0F;YAC1F,qCAAqC;YACrC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACxB,CAAC;IACF,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { IEvent } from \"@fluidframework/core-interfaces\";\n\nimport { IAgentScheduler } from \"./agent.js\";\n\n/**\n * Events emitted by {@link TaskSubscription}.\n * @legacy\n * @alpha\n */\nexport interface ITaskSubscriptionEvents extends IEvent {\n\t(event: \"gotTask\" | \"lostTask\", listener: () => void);\n}\n\n/**\n * TaskSubscription works with an AgentScheduler to make it easier to monitor a specific task ownership.\n * @legacy\n * @alpha\n */\nexport class TaskSubscription extends TypedEventEmitter<ITaskSubscriptionEvents> {\n\tprivate subscribed: boolean = false;\n\n\t/**\n\t * @param agentScheduler - The AgentScheduler that will be subscribed against\n\t * @param taskId - The string ID of the task to subscribe against\n\t */\n\tconstructor(\n\t\tprivate readonly agentScheduler: IAgentScheduler,\n\t\tpublic readonly taskId: string,\n\t) {\n\t\tsuper();\n\t\tagentScheduler.on(\"picked\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"gotTask\");\n\t\t\t}\n\t\t});\n\t\tagentScheduler.on(\"released\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"lostTask\");\n\t\t\t}\n\t\t});\n\t\tagentScheduler.on(\"lost\", (_taskId: string) => {\n\t\t\tif (_taskId === this.taskId) {\n\t\t\t\tthis.emit(\"lostTask\");\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Check if currently holding ownership of the task.\n\t * @returns true if currently the task owner, false otherwise.\n\t */\n\tpublic haveTask(): boolean {\n\t\treturn this.agentScheduler.pickedTasks().includes(this.taskId);\n\t}\n\n\t/**\n\t * Volunteer for the task. By default, the TaskSubscription will only watch the task and not volunteer.\n\t * This is safe to call multiple times across multiple TaskSubscriptions.\n\t */\n\tpublic volunteer(): void {\n\t\tif (!this.subscribed) {\n\t\t\t// AgentScheduler throws if the same task is picked twice but we don't care because our\n\t\t\t// worker does nothing. We only care that the AgentScheduler is trying to pick.\n\t\t\t// We also don't care if we throw due to failing the interactive check, because then we'll\n\t\t\t// just appear to never get the task.\n\t\t\tthis.agentScheduler.pick(this.taskId, async () => {}).catch(() => {});\n\t\t\tthis.subscribed = true;\n\t\t}\n\t}\n}\n"]}
|
package/lib/tsdoc-metadata.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/agent-scheduler",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.31.0",
|
|
4
4
|
"description": "Built in runtime object for distributing agents across instances of a container",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -47,34 +47,33 @@
|
|
|
47
47
|
"main": "lib/index.js",
|
|
48
48
|
"types": "lib/public.d.ts",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@fluid-internal/client-utils": "~2.
|
|
51
|
-
"@fluidframework/container-definitions": "~2.
|
|
52
|
-
"@fluidframework/core-interfaces": "~2.
|
|
53
|
-
"@fluidframework/core-utils": "~2.
|
|
54
|
-
"@fluidframework/datastore": "~2.
|
|
55
|
-
"@fluidframework/datastore-definitions": "~2.
|
|
56
|
-
"@fluidframework/map": "~2.
|
|
57
|
-
"@fluidframework/register-collection": "~2.
|
|
58
|
-
"@fluidframework/runtime-definitions": "~2.
|
|
59
|
-
"@fluidframework/runtime-utils": "~2.
|
|
60
|
-
"@fluidframework/telemetry-utils": "~2.
|
|
50
|
+
"@fluid-internal/client-utils": "~2.31.0",
|
|
51
|
+
"@fluidframework/container-definitions": "~2.31.0",
|
|
52
|
+
"@fluidframework/core-interfaces": "~2.31.0",
|
|
53
|
+
"@fluidframework/core-utils": "~2.31.0",
|
|
54
|
+
"@fluidframework/datastore": "~2.31.0",
|
|
55
|
+
"@fluidframework/datastore-definitions": "~2.31.0",
|
|
56
|
+
"@fluidframework/map": "~2.31.0",
|
|
57
|
+
"@fluidframework/register-collection": "~2.31.0",
|
|
58
|
+
"@fluidframework/runtime-definitions": "~2.31.0",
|
|
59
|
+
"@fluidframework/runtime-utils": "~2.31.0",
|
|
60
|
+
"@fluidframework/telemetry-utils": "~2.31.0",
|
|
61
61
|
"uuid": "^9.0.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@arethetypeswrong/cli": "^0.17.1",
|
|
65
65
|
"@biomejs/biome": "~1.9.3",
|
|
66
66
|
"@fluid-tools/build-cli": "^0.54.0",
|
|
67
|
-
"@fluidframework/agent-scheduler-previous": "npm:@fluidframework/agent-scheduler@2.
|
|
67
|
+
"@fluidframework/agent-scheduler-previous": "npm:@fluidframework/agent-scheduler@2.30.0",
|
|
68
68
|
"@fluidframework/build-common": "^2.0.3",
|
|
69
69
|
"@fluidframework/build-tools": "^0.54.0",
|
|
70
70
|
"@fluidframework/eslint-config-fluid": "^5.7.3",
|
|
71
|
-
"@microsoft/api-extractor": "7.
|
|
71
|
+
"@microsoft/api-extractor": "7.50.1",
|
|
72
72
|
"@types/node": "^18.19.0",
|
|
73
73
|
"@types/uuid": "^9.0.2",
|
|
74
74
|
"concurrently": "^8.2.1",
|
|
75
75
|
"copyfiles": "^2.4.1",
|
|
76
76
|
"eslint": "~8.55.0",
|
|
77
|
-
"prettier": "~3.0.3",
|
|
78
77
|
"rimraf": "^4.4.0",
|
|
79
78
|
"typescript": "~5.4.5"
|
|
80
79
|
},
|
|
@@ -105,7 +104,6 @@
|
|
|
105
104
|
"check:exports:esm:legacy": "api-extractor run --config api-extractor/api-extractor-lint-legacy.esm.json",
|
|
106
105
|
"check:exports:esm:public": "api-extractor run --config api-extractor/api-extractor-lint-public.esm.json",
|
|
107
106
|
"check:format": "npm run check:biome",
|
|
108
|
-
"check:prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore",
|
|
109
107
|
"ci:build:api-reports": "concurrently \"npm:ci:build:api-reports:*\"",
|
|
110
108
|
"ci:build:api-reports:current": "api-extractor run --config api-extractor/api-extractor.current.json",
|
|
111
109
|
"ci:build:api-reports:legacy": "api-extractor run --config api-extractor/api-extractor.legacy.json",
|
|
@@ -116,7 +114,6 @@
|
|
|
116
114
|
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
117
115
|
"format": "npm run format:biome",
|
|
118
116
|
"format:biome": "biome check . --write",
|
|
119
|
-
"format:prettier": "prettier --write . --cache --ignore-path ../../../.prettierignore",
|
|
120
117
|
"lint": "fluid-build . --task lint",
|
|
121
118
|
"lint:fix": "fluid-build . --task eslint:fix --task format",
|
|
122
119
|
"tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
|
package/src/scheduler.ts
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
7
7
|
import { AttachState } from "@fluidframework/container-definitions";
|
|
8
|
-
import {
|
|
8
|
+
import type {
|
|
9
|
+
FluidObject,
|
|
10
|
+
IFluidHandle,
|
|
11
|
+
IFluidLoadable,
|
|
12
|
+
IRequest,
|
|
13
|
+
IResponse,
|
|
14
|
+
} from "@fluidframework/core-interfaces";
|
|
9
15
|
import { assert } from "@fluidframework/core-utils/internal";
|
|
10
16
|
import {
|
|
11
17
|
FluidDataStoreRuntime,
|
|
@@ -36,14 +42,14 @@ import { IAgentScheduler, IAgentSchedulerEvents } from "./agent.js";
|
|
|
36
42
|
// Note: making sure this ID is unique and does not collide with storage provided clientID
|
|
37
43
|
const UnattachedClientId = `${uuid()}_unattached`;
|
|
38
44
|
|
|
39
|
-
const mapWait = async <T =
|
|
45
|
+
const mapWait = async <T = unknown>(map: ISharedMap, key: string): Promise<T> => {
|
|
40
46
|
const maybeValue = map.get<T>(key);
|
|
41
47
|
if (maybeValue !== undefined) {
|
|
42
48
|
return maybeValue;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
return new Promise((resolve) => {
|
|
46
|
-
const handler = (changed: IValueChanged) => {
|
|
52
|
+
const handler = (changed: IValueChanged): void => {
|
|
47
53
|
if (changed.key === key) {
|
|
48
54
|
map.off("valueChanged", handler);
|
|
49
55
|
const value = map.get<T>(changed.key);
|
|
@@ -67,16 +73,10 @@ export class AgentScheduler
|
|
|
67
73
|
runtime: IFluidDataStoreRuntime,
|
|
68
74
|
context: IFluidDataStoreContext,
|
|
69
75
|
existing: boolean,
|
|
70
|
-
) {
|
|
76
|
+
): Promise<IAgentScheduler> {
|
|
71
77
|
let root: ISharedMap;
|
|
72
78
|
let consensusRegisterCollection: ConsensusRegisterCollection<string | null>;
|
|
73
|
-
if (
|
|
74
|
-
root = SharedMap.create(runtime, "root");
|
|
75
|
-
root.bindToContext();
|
|
76
|
-
consensusRegisterCollection = ConsensusRegisterCollection.create(runtime);
|
|
77
|
-
consensusRegisterCollection.bindToContext();
|
|
78
|
-
root.set(schedulerId, consensusRegisterCollection.handle);
|
|
79
|
-
} else {
|
|
79
|
+
if (existing) {
|
|
80
80
|
root = (await runtime.getChannel("root")) as ISharedMap;
|
|
81
81
|
const handle = await mapWait<IFluidHandle<ConsensusRegisterCollection<string | null>>>(
|
|
82
82
|
root,
|
|
@@ -84,6 +84,13 @@ export class AgentScheduler
|
|
|
84
84
|
);
|
|
85
85
|
assert(handle !== undefined, 0x116 /* "Missing handle on scheduler load" */);
|
|
86
86
|
consensusRegisterCollection = await handle.get();
|
|
87
|
+
} else {
|
|
88
|
+
root = SharedMap.create(runtime, "root");
|
|
89
|
+
root.bindToContext();
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
91
|
+
consensusRegisterCollection = ConsensusRegisterCollection.create(runtime);
|
|
92
|
+
consensusRegisterCollection.bindToContext();
|
|
93
|
+
root.set(schedulerId, consensusRegisterCollection.handle);
|
|
87
94
|
}
|
|
88
95
|
const agentScheduler = new AgentScheduler(runtime, context, consensusRegisterCollection);
|
|
89
96
|
agentScheduler.initialize();
|
|
@@ -91,10 +98,10 @@ export class AgentScheduler
|
|
|
91
98
|
return agentScheduler;
|
|
92
99
|
}
|
|
93
100
|
|
|
94
|
-
public get IAgentScheduler() {
|
|
101
|
+
public get IAgentScheduler(): IAgentScheduler {
|
|
95
102
|
return this;
|
|
96
103
|
}
|
|
97
|
-
public get IFluidLoadable() {
|
|
104
|
+
public get IFluidLoadable(): IFluidLoadable {
|
|
98
105
|
return this;
|
|
99
106
|
}
|
|
100
107
|
|
|
@@ -138,7 +145,7 @@ export class AgentScheduler
|
|
|
138
145
|
this._handle = new FluidObjectHandle(this, "", this.runtime.objectsRoutingContext);
|
|
139
146
|
}
|
|
140
147
|
|
|
141
|
-
public get handle() {
|
|
148
|
+
public get handle(): IFluidHandle<this> {
|
|
142
149
|
return this._handle;
|
|
143
150
|
}
|
|
144
151
|
|
|
@@ -210,9 +217,9 @@ export class AgentScheduler
|
|
|
210
217
|
}
|
|
211
218
|
|
|
212
219
|
public pickedTasks(): string[] {
|
|
213
|
-
return
|
|
220
|
+
return [...this.runningTasks.values()];
|
|
214
221
|
}
|
|
215
|
-
|
|
222
|
+
/* eslint-disable unicorn/no-null */
|
|
216
223
|
private async registerCore(taskUrls: string[]): Promise<void> {
|
|
217
224
|
if (taskUrls.length > 0) {
|
|
218
225
|
const registersP: Promise<void>[] = [];
|
|
@@ -231,7 +238,7 @@ export class AgentScheduler
|
|
|
231
238
|
}
|
|
232
239
|
}
|
|
233
240
|
|
|
234
|
-
private async releaseCore(taskUrls: string[]) {
|
|
241
|
+
private async releaseCore(taskUrls: string[]): Promise<void> {
|
|
235
242
|
if (taskUrls.length > 0) {
|
|
236
243
|
const releasesP: Promise<void>[] = [];
|
|
237
244
|
for (const taskUrl of taskUrls) {
|
|
@@ -243,7 +250,7 @@ export class AgentScheduler
|
|
|
243
250
|
}
|
|
244
251
|
}
|
|
245
252
|
|
|
246
|
-
private async clearTasks(taskUrls: string[]) {
|
|
253
|
+
private async clearTasks(taskUrls: string[]): Promise<void> {
|
|
247
254
|
assert(this.isActive(), 0x11b /* "Trying to clear tasks on inactive agent" */);
|
|
248
255
|
const clearP: Promise<void>[] = [];
|
|
249
256
|
for (const taskUrl of taskUrls) {
|
|
@@ -260,7 +267,7 @@ export class AgentScheduler
|
|
|
260
267
|
await this.consensusRegisterCollection.write(key, clientId);
|
|
261
268
|
}
|
|
262
269
|
|
|
263
|
-
private initialize() {
|
|
270
|
+
private initialize(): void {
|
|
264
271
|
const quorum = this.runtime.getQuorum();
|
|
265
272
|
// A client left the quorum. Iterate and clear tasks held by that client.
|
|
266
273
|
// Ideally a leader should do this cleanup. But it's complicated when a leader itself leaves.
|
|
@@ -271,7 +278,7 @@ export class AgentScheduler
|
|
|
271
278
|
if (!this.runtime.objectsRoutingContext.isAttached) return;
|
|
272
279
|
// Cleanup only if connected. If not, cleanup will happen in initializeCore() that runs on connection.
|
|
273
280
|
if (this.isActive()) {
|
|
274
|
-
const tasks: Promise<
|
|
281
|
+
const tasks: Promise<unknown>[] = [];
|
|
275
282
|
const leftTasks: string[] = [];
|
|
276
283
|
for (const taskUrl of this.consensusRegisterCollection.keys()) {
|
|
277
284
|
if (this.getTaskClientId(taskUrl) === clientId) {
|
|
@@ -339,7 +346,7 @@ export class AgentScheduler
|
|
|
339
346
|
});
|
|
340
347
|
}
|
|
341
348
|
|
|
342
|
-
private onNewTaskAssigned(key: string) {
|
|
349
|
+
private onNewTaskAssigned(key: string): void {
|
|
343
350
|
assert(!this.runningTasks.has(key), 0x11d /* "task is already running" */);
|
|
344
351
|
this.runningTasks.add(key);
|
|
345
352
|
const worker = this.locallyRunnableTasks.get(key);
|
|
@@ -353,7 +360,7 @@ export class AgentScheduler
|
|
|
353
360
|
}
|
|
354
361
|
}
|
|
355
362
|
|
|
356
|
-
private async onTaskReassigned(key: string, currentClient: string | null) {
|
|
363
|
+
private async onTaskReassigned(key: string, currentClient: string | null): Promise<void> {
|
|
357
364
|
if (this.runningTasks.has(key)) {
|
|
358
365
|
this.runningTasks.delete(key);
|
|
359
366
|
this.emit("released", key);
|
|
@@ -375,8 +382,9 @@ export class AgentScheduler
|
|
|
375
382
|
}
|
|
376
383
|
}
|
|
377
384
|
}
|
|
385
|
+
/* eslint-enable unicorn/no-null */
|
|
378
386
|
|
|
379
|
-
private isActive() {
|
|
387
|
+
private isActive(): boolean {
|
|
380
388
|
// Scheduler should be active in detached container.
|
|
381
389
|
if (this.runtime.attachState === AttachState.Detached) {
|
|
382
390
|
return true;
|
|
@@ -391,11 +399,11 @@ export class AgentScheduler
|
|
|
391
399
|
return this.context.deltaManager.active;
|
|
392
400
|
}
|
|
393
401
|
|
|
394
|
-
private initializeCore() {
|
|
402
|
+
private initializeCore(): void {
|
|
395
403
|
// Nobody released the tasks held by last client in previous session.
|
|
396
404
|
// Check to see if this client needs to do this.
|
|
397
405
|
const clearCandidates: string[] = [];
|
|
398
|
-
const tasks: Promise<
|
|
406
|
+
const tasks: Promise<unknown>[] = [];
|
|
399
407
|
|
|
400
408
|
for (const [taskUrl] of this.locallyRunnableTasks) {
|
|
401
409
|
if (!this.getTaskClientId(taskUrl)) {
|
|
@@ -417,7 +425,7 @@ export class AgentScheduler
|
|
|
417
425
|
});
|
|
418
426
|
}
|
|
419
427
|
|
|
420
|
-
private clearRunningTasks() {
|
|
428
|
+
private clearRunningTasks(): void {
|
|
421
429
|
const tasks = this.runningTasks;
|
|
422
430
|
this.runningTasks = new Set<string>();
|
|
423
431
|
|
|
@@ -432,7 +440,7 @@ export class AgentScheduler
|
|
|
432
440
|
}
|
|
433
441
|
}
|
|
434
442
|
|
|
435
|
-
private sendErrorEvent(eventName: string, error:
|
|
443
|
+
private sendErrorEvent(eventName: string, error: unknown, key?: string): void {
|
|
436
444
|
this.logger.sendErrorEvent({ eventName, key }, error);
|
|
437
445
|
}
|
|
438
446
|
}
|
|
@@ -447,18 +455,16 @@ class AgentSchedulerRuntime extends FluidDataStoreRuntime {
|
|
|
447
455
|
AgentScheduler.load(this, dataStoreContext, existing),
|
|
448
456
|
);
|
|
449
457
|
}
|
|
450
|
-
public async request(request: IRequest) {
|
|
458
|
+
public async request(request: IRequest): Promise<IResponse> {
|
|
451
459
|
const response = await super.request(request);
|
|
452
|
-
if (response.status === 404) {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
return { status: 200, mimeType: "fluid/object", value: agentScheduler };
|
|
461
|
-
}
|
|
460
|
+
if (response.status === 404 && (request.url === "" || request.url === "/")) {
|
|
461
|
+
const agentScheduler = await this.entryPoint.get();
|
|
462
|
+
assert(
|
|
463
|
+
agentScheduler !== undefined,
|
|
464
|
+
0x466 /* entryPoint for AgentSchedulerRuntime should have been initialized by now */,
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
return { status: 200, mimeType: "fluid/object", value: agentScheduler };
|
|
462
468
|
}
|
|
463
469
|
return response;
|
|
464
470
|
}
|
|
@@ -472,7 +478,7 @@ export class AgentSchedulerFactory implements IFluidDataStoreFactory {
|
|
|
472
478
|
public static readonly type = "_scheduler";
|
|
473
479
|
public readonly type = AgentSchedulerFactory.type;
|
|
474
480
|
|
|
475
|
-
public get IFluidDataStoreFactory() {
|
|
481
|
+
public get IFluidDataStoreFactory(): AgentSchedulerFactory {
|
|
476
482
|
return this;
|
|
477
483
|
}
|
|
478
484
|
|
package/src/taskSubscription.ts
CHANGED
|
@@ -55,7 +55,7 @@ export class TaskSubscription extends TypedEventEmitter<ITaskSubscriptionEvents>
|
|
|
55
55
|
* Check if currently holding ownership of the task.
|
|
56
56
|
* @returns true if currently the task owner, false otherwise.
|
|
57
57
|
*/
|
|
58
|
-
public haveTask() {
|
|
58
|
+
public haveTask(): boolean {
|
|
59
59
|
return this.agentScheduler.pickedTasks().includes(this.taskId);
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -63,7 +63,7 @@ export class TaskSubscription extends TypedEventEmitter<ITaskSubscriptionEvents>
|
|
|
63
63
|
* Volunteer for the task. By default, the TaskSubscription will only watch the task and not volunteer.
|
|
64
64
|
* This is safe to call multiple times across multiple TaskSubscriptions.
|
|
65
65
|
*/
|
|
66
|
-
public volunteer() {
|
|
66
|
+
public volunteer(): void {
|
|
67
67
|
if (!this.subscribed) {
|
|
68
68
|
// AgentScheduler throws if the same task is picked twice but we don't care because our
|
|
69
69
|
// worker does nothing. We only care that the AgentScheduler is trying to pick.
|