@fluidframework/agent-scheduler 1.4.0-121020 → 2.0.0-dev-rc.1.0.0.225277

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/.eslintrc.js +8 -10
  2. package/CHANGELOG.md +124 -0
  3. package/README.md +39 -3
  4. package/api-extractor-esm.json +4 -0
  5. package/api-extractor-lint.json +4 -0
  6. package/api-extractor.json +4 -0
  7. package/api-report/agent-scheduler.api.md +71 -0
  8. package/dist/agent-scheduler-alpha.d.ts +127 -0
  9. package/dist/agent-scheduler-beta.d.ts +30 -0
  10. package/dist/agent-scheduler-public.d.ts +30 -0
  11. package/dist/agent-scheduler-untrimmed.d.ts +127 -0
  12. package/dist/{agent.js → agent.cjs} +4 -1
  13. package/dist/agent.cjs.map +1 -0
  14. package/dist/agent.d.ts +25 -10
  15. package/dist/agent.d.ts.map +1 -1
  16. package/dist/index.cjs +14 -0
  17. package/dist/index.cjs.map +1 -0
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/{scheduler.js → scheduler.cjs} +93 -57
  21. package/dist/scheduler.cjs.map +1 -0
  22. package/dist/scheduler.d.ts +10 -12
  23. package/dist/scheduler.d.ts.map +1 -1
  24. package/dist/{taskSubscription.js → taskSubscription.cjs} +4 -3
  25. package/dist/taskSubscription.cjs.map +1 -0
  26. package/dist/taskSubscription.d.ts +7 -2
  27. package/dist/taskSubscription.d.ts.map +1 -1
  28. package/dist/tsdoc-metadata.json +11 -0
  29. package/lib/agent-scheduler-alpha.d.mts +127 -0
  30. package/lib/agent-scheduler-beta.d.mts +30 -0
  31. package/lib/agent-scheduler-public.d.mts +30 -0
  32. package/lib/agent-scheduler-untrimmed.d.mts +127 -0
  33. package/lib/{agent.d.ts → agent.d.mts} +26 -11
  34. package/lib/agent.d.mts.map +1 -0
  35. package/lib/{agent.js → agent.mjs} +4 -1
  36. package/lib/agent.mjs.map +1 -0
  37. package/lib/index.d.mts +8 -0
  38. package/lib/index.d.mts.map +1 -0
  39. package/lib/index.mjs +8 -0
  40. package/lib/index.mjs.map +1 -0
  41. package/lib/{scheduler.d.ts → scheduler.d.mts} +12 -14
  42. package/lib/scheduler.d.mts.map +1 -0
  43. package/lib/{scheduler.js → scheduler.mjs} +83 -47
  44. package/lib/scheduler.mjs.map +1 -0
  45. package/lib/{taskSubscription.d.ts → taskSubscription.d.mts} +9 -4
  46. package/lib/taskSubscription.d.mts.map +1 -0
  47. package/lib/{taskSubscription.js → taskSubscription.mjs} +3 -2
  48. package/lib/taskSubscription.mjs.map +1 -0
  49. package/package.json +115 -73
  50. package/prettier.config.cjs +8 -0
  51. package/src/agent.ts +63 -45
  52. package/src/index.ts +2 -2
  53. package/src/scheduler.ts +469 -405
  54. package/src/taskSubscription.ts +55 -47
  55. package/tsc-multi.test.json +4 -0
  56. package/tsconfig.json +11 -13
  57. package/dist/agent.js.map +0 -1
  58. package/dist/index.js +0 -22
  59. package/dist/index.js.map +0 -1
  60. package/dist/scheduler.js.map +0 -1
  61. package/dist/taskSubscription.js.map +0 -1
  62. package/lib/agent.d.ts.map +0 -1
  63. package/lib/agent.js.map +0 -1
  64. package/lib/index.d.ts +0 -8
  65. package/lib/index.d.ts.map +0 -1
  66. package/lib/index.js +0 -8
  67. package/lib/index.js.map +0 -1
  68. package/lib/scheduler.d.ts.map +0 -1
  69. package/lib/scheduler.js.map +0 -1
  70. package/lib/taskSubscription.d.ts.map +0 -1
  71. package/lib/taskSubscription.js.map +0 -1
  72. package/tsconfig.esnext.json +0 -7
package/dist/agent.d.ts CHANGED
@@ -2,31 +2,46 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { IEvent, IEventProvider } from "@fluidframework/common-definitions";
5
+ import { IEvent, IEventProvider, IFluidLoadable } from "@fluidframework/core-interfaces";
6
+ /**
7
+ * @alpha
8
+ */
6
9
  export declare const IAgentScheduler: keyof IProvideAgentScheduler;
10
+ /**
11
+ * @alpha
12
+ */
7
13
  export interface IProvideAgentScheduler {
8
14
  readonly IAgentScheduler: IAgentScheduler;
9
15
  }
16
+ /**
17
+ * Events emitted by {@link (IAgentScheduler:interface)}.
18
+ * @alpha
19
+ */
10
20
  export interface IAgentSchedulerEvents extends IEvent {
11
21
  /**
12
22
  * Event when ownership of task changes
13
23
  * @param event - name of the event:
14
- * "picked" - the task has been assigned to this client, in response to pick() being called
15
- * If client loses this task (due to disconnect), it will attempt to pick it again (on connection)
16
- * automatically, unless release() is called
17
- * "released" - the task was successfully released back to the pool. Client will not attempt to
18
- * re-acquire the task, unless pick() is called.
19
- * "lost" - task is lost due to disconnect or data store / container being attached.
20
- * Task will be picked up again by some connected client (this client will try as well,
21
- * unless release() is called)
24
+ *
25
+ * - "picked" - the task has been assigned to this client, in response to pick() being called
26
+ * If client loses this task (due to disconnect), it will attempt to pick it again (on connection)
27
+ * automatically, unless release() is called
28
+ *
29
+ * - "released" - the task was successfully released back to the pool. Client will not attempt to
30
+ * re-acquire the task, unless pick() is called.
31
+ *
32
+ * - "lost" - task is lost due to disconnect or data store / container being attached.
33
+ * Task will be picked up again by some connected client (this client will try as well,
34
+ * unless release() is called)
35
+ *
22
36
  * @param listener - callback notified when change happened for particular key
23
37
  */
24
38
  (event: "picked" | "released" | "lost", listener: (taskId: string) => void): any;
25
39
  }
26
40
  /**
27
41
  * Agent scheduler distributes a set of tasks/variables across connected clients.
42
+ * @alpha
28
43
  */
29
- export interface IAgentScheduler extends IProvideAgentScheduler, IEventProvider<IAgentSchedulerEvents> {
44
+ export interface IAgentScheduler extends IProvideAgentScheduler, IEventProvider<IAgentSchedulerEvents>, IFluidLoadable {
30
45
  /**
31
46
  * Registers a set of new tasks to distribute amongst connected clients. Only use this if a client wants
32
47
  * a new agent to run but does not have the capability to run the agent inside the host.
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAE5E,eAAO,MAAM,eAAe,EAAE,MAAM,sBAA0C,CAAC;AAE/E,MAAM,WAAW,sBAAsB;IACnC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC7C;AAED,MAAM,WAAW,qBAAsB,SAAQ,MAAM;IACjD;;;;;;;;;;;;OAYG;IACH,CAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,OAAE;CAC/E;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,sBAAsB,EAAE,cAAc,CAAC,qBAAqB,CAAC;IAClG;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C;;;;;;;OAOG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjE;;;;;OAKG;IACH,OAAO,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,WAAW,IAAI,MAAM,EAAE,CAAC;CAC3B"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEzF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,sBAA0C,CAAC;AAE/E;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAsB,SAAQ,MAAM;IACpD;;;;;;;;;;;;;;;;OAgBG;IACH,CAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,OAAE;CAC5E;AAED;;;GAGG;AACH,MAAM,WAAW,eAChB,SAAQ,sBAAsB,EAC7B,cAAc,CAAC,qBAAqB,CAAC,EACrC,cAAc;IACf;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C;;;;;;;OAOG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjE;;;;;OAKG;IACH,OAAO,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,WAAW,IAAI,MAAM,EAAE,CAAC;CACxB"}
package/dist/index.cjs ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.TaskSubscription = exports.AgentSchedulerFactory = exports.IAgentScheduler = void 0;
8
+ var agent_1 = require("./agent.cjs");
9
+ Object.defineProperty(exports, "IAgentScheduler", { enumerable: true, get: function () { return agent_1.IAgentScheduler; } });
10
+ var scheduler_1 = require("./scheduler.cjs");
11
+ Object.defineProperty(exports, "AgentSchedulerFactory", { enumerable: true, get: function () { return scheduler_1.AgentSchedulerFactory; } });
12
+ var taskSubscription_1 = require("./taskSubscription.cjs");
13
+ Object.defineProperty(exports, "TaskSubscription", { enumerable: true, get: function () { return taskSubscription_1.TaskSubscription; } });
14
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,qCAAyF;AAAhF,wGAAA,eAAe,OAAA;AACxB,6CAAoD;AAA3C,kHAAA,qBAAqB,OAAA;AAC9B,2DAA+E;AAA7C,oHAAA,gBAAgB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { IAgentScheduler, IAgentSchedulerEvents, IProvideAgentScheduler } from \"./agent\";\nexport { AgentSchedulerFactory } from \"./scheduler\";\nexport { ITaskSubscriptionEvents, TaskSubscription } from \"./taskSubscription\";\n"]}
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- export * from "./agent";
5
+ export { IAgentScheduler, IAgentSchedulerEvents, IProvideAgentScheduler } from "./agent";
6
6
  export { AgentSchedulerFactory } from "./scheduler";
7
- export * from "./taskSubscription";
7
+ export { ITaskSubscriptionEvents, TaskSubscription } from "./taskSubscription";
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -5,13 +5,14 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.AgentSchedulerFactory = exports.AgentScheduler = void 0;
8
- const common_utils_1 = require("@fluidframework/common-utils");
8
+ const client_utils_1 = require("@fluid-internal/client-utils");
9
+ const core_utils_1 = require("@fluidframework/core-utils");
9
10
  const datastore_1 = require("@fluidframework/datastore");
10
11
  const container_definitions_1 = require("@fluidframework/container-definitions");
11
12
  const map_1 = require("@fluidframework/map");
12
13
  const register_collection_1 = require("@fluidframework/register-collection");
13
- const runtime_utils_1 = require("@fluidframework/runtime-utils");
14
14
  const uuid_1 = require("uuid");
15
+ const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
15
16
  // Note: making sure this ID is unique and does not collide with storage provided clientID
16
17
  const UnattachedClientId = `${(0, uuid_1.v4)()}_unattached`;
17
18
  const mapWait = async (map, key) => {
@@ -34,26 +35,7 @@ const mapWait = async (map, key) => {
34
35
  });
35
36
  };
36
37
  const schedulerId = "scheduler";
37
- class AgentScheduler extends common_utils_1.TypedEventEmitter {
38
- constructor(runtime, context, consensusRegisterCollection) {
39
- super();
40
- this.runtime = runtime;
41
- this.context = context;
42
- this.consensusRegisterCollection = consensusRegisterCollection;
43
- // Set of tasks registered by this client.
44
- // Has no relationship with lists below.
45
- // The only requirement here - a task can be registered by a client only once.
46
- // Other clients can pick these tasks.
47
- this.registeredTasks = new Set();
48
- // List of all tasks client is capable of running (essentially expressed desire to run)
49
- // Client will proactively attempt to pick them up these tasks if they are not assigned to other clients.
50
- // This is a strict superset of tasks running in the client.
51
- this.locallyRunnableTasks = new Map();
52
- // Set of registered tasks client is currently running.
53
- // It's subset of this.locallyRunnableTasks
54
- this.runningTasks = new Set();
55
- this._handle = new datastore_1.FluidObjectHandle(this, "", this.runtime.objectsRoutingContext);
56
- }
38
+ class AgentScheduler extends client_utils_1.TypedEventEmitter {
57
39
  static async load(runtime, context, existing) {
58
40
  let root;
59
41
  let consensusRegisterCollection;
@@ -65,31 +47,57 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
65
47
  root.set(schedulerId, consensusRegisterCollection.handle);
66
48
  }
67
49
  else {
68
- root = await runtime.getChannel("root");
50
+ root = (await runtime.getChannel("root"));
69
51
  const handle = await mapWait(root, schedulerId);
70
- (0, common_utils_1.assert)(handle !== undefined, 0x116 /* "Missing handle on scheduler load" */);
52
+ (0, core_utils_1.assert)(handle !== undefined, 0x116 /* "Missing handle on scheduler load" */);
71
53
  consensusRegisterCollection = await handle.get();
72
54
  }
73
55
  const agentScheduler = new AgentScheduler(runtime, context, consensusRegisterCollection);
74
56
  agentScheduler.initialize();
75
57
  return agentScheduler;
76
58
  }
77
- get IAgentScheduler() { return this; }
59
+ get IAgentScheduler() {
60
+ return this;
61
+ }
62
+ get IFluidLoadable() {
63
+ return this;
64
+ }
78
65
  get clientId() {
79
66
  if (this.runtime.attachState === container_definitions_1.AttachState.Detached) {
80
67
  return UnattachedClientId;
81
68
  }
82
69
  const clientId = this.runtime.clientId;
83
- (0, common_utils_1.assert)(!!clientId, 0x117 /* "Trying to get missing clientId!" */);
70
+ (0, core_utils_1.assert)(!!clientId, 0x117 /* "Trying to get missing clientId!" */);
84
71
  return clientId;
85
72
  }
73
+ constructor(runtime, context, consensusRegisterCollection) {
74
+ super();
75
+ this.runtime = runtime;
76
+ this.context = context;
77
+ this.consensusRegisterCollection = consensusRegisterCollection;
78
+ // Set of tasks registered by this client.
79
+ // Has no relationship with lists below.
80
+ // The only requirement here - a task can be registered by a client only once.
81
+ // Other clients can pick these tasks.
82
+ this.registeredTasks = new Set();
83
+ // List of all tasks client is capable of running (essentially expressed desire to run)
84
+ // Client will proactively attempt to pick them up these tasks if they are not assigned to other clients.
85
+ // This is a strict superset of tasks running in the client.
86
+ this.locallyRunnableTasks = new Map();
87
+ // Set of registered tasks client is currently running.
88
+ // It's subset of this.locallyRunnableTasks
89
+ this.runningTasks = new Set();
90
+ // We are expecting this class to have many listeners, so we suppress noisy "MaxListenersExceededWarning" logging.
91
+ super.setMaxListeners(0);
92
+ this._handle = new datastore_1.FluidObjectHandle(this, "", this.runtime.objectsRoutingContext);
93
+ }
86
94
  get handle() {
87
95
  return this._handle;
88
96
  }
89
97
  async register(...taskUrls) {
90
98
  for (const taskUrl of taskUrls) {
91
99
  if (this.registeredTasks.has(taskUrl)) {
92
- throw new Error(`${taskUrl} is already registered`);
100
+ throw new telemetry_utils_1.UsageError(`Task is already registered`, (0, telemetry_utils_1.tagCodeArtifacts)({ taskUrl }));
93
101
  }
94
102
  }
95
103
  const unregisteredTasks = [];
@@ -103,20 +111,20 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
103
111
  }
104
112
  return this.registerCore(unregisteredTasks);
105
113
  }
106
- async pick(taskId, worker) {
107
- if (this.locallyRunnableTasks.has(taskId)) {
108
- throw new Error(`${taskId} is already attempted`);
114
+ async pick(taskUrl, worker) {
115
+ if (this.locallyRunnableTasks.has(taskUrl)) {
116
+ throw new telemetry_utils_1.UsageError(`Task is already attempted`, (0, telemetry_utils_1.tagCodeArtifacts)({ taskUrl }));
109
117
  }
110
- this.locallyRunnableTasks.set(taskId, worker);
118
+ this.locallyRunnableTasks.set(taskUrl, worker);
111
119
  // We have a policy to disallow non-interactive clients from taking tasks. Callers of pick() can
112
120
  // either perform this check proactively and call conditionally, or catch the error (in which case
113
121
  // they can know they will not get the task).
114
- (0, common_utils_1.assert)(this.context.deltaManager.clientDetails.capabilities.interactive, 0x118 /* "Bad client interactive check" */);
122
+ (0, core_utils_1.assert)(this.context.deltaManager.clientDetails.capabilities.interactive, 0x118 /* "Bad client interactive check" */);
115
123
  // Check the current status and express interest if it's a new one (undefined) or currently unpicked (null).
116
124
  if (this.isActive()) {
117
- const currentClient = this.getTaskClientId(taskId);
125
+ const currentClient = this.getTaskClientId(taskUrl);
118
126
  if (currentClient === undefined || currentClient === null) {
119
- await this.writeCore(taskId, this.clientId);
127
+ await this.writeCore(taskUrl, this.clientId);
120
128
  }
121
129
  }
122
130
  }
@@ -124,13 +132,23 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
124
132
  const active = this.isActive();
125
133
  for (const taskUrl of taskUrls) {
126
134
  if (!this.locallyRunnableTasks.has(taskUrl)) {
127
- throw new Error(`${taskUrl} was never registered`);
135
+ throw new telemetry_utils_1.UsageError(`Task was never registered`, (0, telemetry_utils_1.tagCodeArtifacts)({ taskUrl }));
136
+ }
137
+ if (!this.runningTasks.has(taskUrl)) {
138
+ // If we got disconnected (and are attached), tasks that we WERE picked for at the time of disconnect
139
+ // will still show us as holding the task according to getTaskClientId (the CRC is stale), but we
140
+ // should not try to release because our disconnect will already result in either someone else or
141
+ // ourselves clearing the task upon reconnect.
142
+ // This UsageError is to enforce that the caller should check AgentScheduler.pickedTasks before trying
143
+ // to release a task.
144
+ throw new telemetry_utils_1.UsageError(`Task is not currently picked`, (0, telemetry_utils_1.tagCodeArtifacts)({ taskUrl }));
128
145
  }
129
- // Note - the assumption is - we are connected.
130
- // If not - all tasks should have been dropped already on disconnect / attachment
131
- (0, common_utils_1.assert)(active, 0x119 /* "This agent became inactive while releasing" */);
146
+ // We may only release tasks that we KNOW we hold (detached state or connected and own the CRC). If we're
147
+ // attached+disconnected then we'll lose the task automatically, and so may not release manually (someone
148
+ // else might hold it by the time we reconnect)
149
+ (0, core_utils_1.assert)(active, 0x119 /* "This agent became inactive while releasing" */);
132
150
  if (this.getTaskClientId(taskUrl) !== this.clientId) {
133
- throw new Error(`${taskUrl} was never picked`);
151
+ throw new telemetry_utils_1.UsageError(`Task was never picked`, (0, telemetry_utils_1.tagCodeArtifacts)({ taskUrl }));
134
152
  }
135
153
  }
136
154
  return this.releaseCore([...taskUrls]);
@@ -149,7 +167,7 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
149
167
  for (const taskUrl of taskUrls) {
150
168
  const taskStatus = this.getTaskClientId(taskUrl);
151
169
  // Task should be either registered (null) or picked up.
152
- (0, common_utils_1.assert)(taskStatus !== undefined, 0x11a /* `Unsuccessful registration` */);
170
+ (0, core_utils_1.assert)(taskStatus !== undefined, 0x11a /* `Unsuccessful registration` */);
153
171
  }
154
172
  }
155
173
  }
@@ -165,7 +183,7 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
165
183
  }
166
184
  }
167
185
  async clearTasks(taskUrls) {
168
- (0, common_utils_1.assert)(this.isActive(), 0x11b /* "Trying to clear tasks on inactive agent" */);
186
+ (0, core_utils_1.assert)(this.isActive(), 0x11b /* "Trying to clear tasks on inactive agent" */);
169
187
  const clearP = [];
170
188
  for (const taskUrl of taskUrls) {
171
189
  clearP.push(this.writeCore(taskUrl, null));
@@ -185,7 +203,7 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
185
203
  // Probably okay for now to have every client try to do this.
186
204
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
187
205
  quorum.on("removeMember", async (clientId) => {
188
- (0, common_utils_1.assert)(this.runtime.objectsRoutingContext.isAttached, 0x11c /* "Detached object routing context" */);
206
+ (0, core_utils_1.assert)(this.runtime.objectsRoutingContext.isAttached, 0x11c /* "Detached object routing context" */);
189
207
  // Cleanup only if connected. If not, cleanup will happen in initializeCore() that runs on connection.
190
208
  if (this.isActive()) {
191
209
  const tasks = [];
@@ -208,14 +226,22 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
208
226
  });
209
227
  // Listeners for new/released tasks. All clients will try to grab at the same time.
210
228
  // May be we want a randomized timer (Something like raft) to reduce chattiness?
229
+ this.consensusRegisterCollection.on("atomicChanged",
211
230
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
212
- this.consensusRegisterCollection.on("atomicChanged", async (key, currentClient) => {
231
+ async (key, currentClient) => {
213
232
  // Check if this client was chosen.
214
233
  if (this.isActive() && currentClient === this.clientId) {
215
234
  this.onNewTaskAssigned(key);
216
235
  }
217
236
  else {
218
- await this.onTaskReassigned(key, currentClient);
237
+ // The call below mutates the consensusRegisterCollection in
238
+ // its event handler, which is not safe.
239
+ // We need to force this to be part of a different batch of ops by
240
+ // scheduling a microtask in order to work around the current validations.
241
+ // This is not recommended and should be avoided.
242
+ await Promise.resolve().then(async () => {
243
+ await this.onTaskReassigned(key, currentClient);
244
+ });
219
245
  }
220
246
  });
221
247
  if (this.isActive()) {
@@ -227,9 +253,12 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
227
253
  }
228
254
  });
229
255
  if (this.runtime.attachState === container_definitions_1.AttachState.Detached) {
230
- this.runtime.waitAttached().then(() => {
256
+ this.runtime
257
+ .waitAttached()
258
+ .then(() => {
231
259
  this.clearRunningTasks();
232
- }).catch((error) => {
260
+ })
261
+ .catch((error) => {
233
262
  this.sendErrorEvent("AgentScheduler_clearRunningTasks", error);
234
263
  });
235
264
  }
@@ -240,7 +269,7 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
240
269
  });
241
270
  }
242
271
  onNewTaskAssigned(key) {
243
- (0, common_utils_1.assert)(!this.runningTasks.has(key), 0x11d /* "task is already running" */);
272
+ (0, core_utils_1.assert)(!this.runningTasks.has(key), 0x11d /* "task is already running" */);
244
273
  this.runningTasks.add(key);
245
274
  const worker = this.locallyRunnableTasks.get(key);
246
275
  if (worker === undefined) {
@@ -258,8 +287,7 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
258
287
  this.runningTasks.delete(key);
259
288
  this.emit("released", key);
260
289
  }
261
- (0, common_utils_1.assert)(currentClient !== undefined, 0x11e /* "client is undefined" */);
262
- /* eslint-disable @typescript-eslint/brace-style */
290
+ (0, core_utils_1.assert)(currentClient !== undefined, 0x11e /* "client is undefined" */);
263
291
  if (this.isActive()) {
264
292
  // attempt to pick up task if we are connected.
265
293
  // If not, initializeCore() will do it when connected
@@ -275,7 +303,6 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
275
303
  await this.writeCore(key, null);
276
304
  }
277
305
  }
278
- /* eslint-enable @typescript-eslint/brace-style */
279
306
  }
280
307
  isActive() {
281
308
  // Scheduler should be active in detached container.
@@ -329,32 +356,41 @@ class AgentScheduler extends common_utils_1.TypedEventEmitter {
329
356
  exports.AgentScheduler = AgentScheduler;
330
357
  class AgentSchedulerRuntime extends datastore_1.FluidDataStoreRuntime {
331
358
  constructor(dataStoreContext, sharedObjectRegistry, existing) {
332
- super(dataStoreContext, sharedObjectRegistry, existing);
333
- this.agentSchedulerP = AgentScheduler.load(this, dataStoreContext, existing);
359
+ super(dataStoreContext, sharedObjectRegistry, existing, async () => AgentScheduler.load(this, dataStoreContext, existing));
334
360
  }
335
361
  async request(request) {
336
362
  const response = await super.request(request);
337
363
  if (response.status === 404) {
338
364
  if (request.url === "" || request.url === "/") {
339
- const agentScheduler = await this.agentSchedulerP;
365
+ const agentScheduler = await this.entryPoint.get();
366
+ (0, core_utils_1.assert)(agentScheduler !== undefined, 0x466 /* entryPoint for AgentSchedulerRuntime should have been initialized by now */);
340
367
  return { status: 200, mimeType: "fluid/object", value: agentScheduler };
341
368
  }
342
369
  }
343
370
  return response;
344
371
  }
345
372
  }
373
+ /**
374
+ * @alpha
375
+ */
346
376
  class AgentSchedulerFactory {
347
377
  constructor() {
348
378
  this.type = AgentSchedulerFactory.type;
349
379
  }
350
- get IFluidDataStoreFactory() { return this; }
380
+ get IFluidDataStoreFactory() {
381
+ return this;
382
+ }
351
383
  static get registryEntry() {
352
384
  return [this.type, Promise.resolve(new AgentSchedulerFactory())];
353
385
  }
354
386
  static async createChildInstance(parentContext) {
355
387
  const packagePath = [...parentContext.packagePath, AgentSchedulerFactory.type];
356
- const router = await parentContext.containerRuntime.createDataStore(packagePath);
357
- return (0, runtime_utils_1.requestFluidObject)(router, "/");
388
+ const dataStore = await parentContext.containerRuntime.createDataStore(packagePath);
389
+ const entryPoint = await dataStore.entryPoint.get();
390
+ // AgentSchedulerRuntime always puts an AgentScheduler object in the data store's entryPoint, but double-check
391
+ // while we plumb entryPoints correctly everywhere, so we can be sure the cast below is fine.
392
+ (0, core_utils_1.assert)(entryPoint.IAgentScheduler !== undefined, 0x467 /* The data store's entryPoint is not an AgentScheduler! */);
393
+ return entryPoint;
358
394
  }
359
395
  async instantiateDataStore(context, existing) {
360
396
  const mapFactory = map_1.SharedMap.getFactory();
@@ -367,4 +403,4 @@ class AgentSchedulerFactory {
367
403
  }
368
404
  exports.AgentSchedulerFactory = AgentSchedulerFactory;
369
405
  AgentSchedulerFactory.type = "_scheduler";
370
- //# sourceMappingURL=scheduler.js.map
406
+ //# sourceMappingURL=scheduler.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.cjs","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 { assert } from \"@fluidframework/core-utils\";\nimport { FluidObject, IFluidHandle, IRequest } from \"@fluidframework/core-interfaces\";\nimport {\n\tFluidDataStoreRuntime,\n\tFluidObjectHandle,\n\tISharedObjectRegistry,\n} from \"@fluidframework/datastore\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { ISharedMap, IValueChanged, SharedMap } from \"@fluidframework/map\";\nimport { ConsensusRegisterCollection } from \"@fluidframework/register-collection\";\nimport { IFluidDataStoreRuntime, IChannelFactory } from \"@fluidframework/datastore-definitions\";\nimport {\n\tIFluidDataStoreContext,\n\tIFluidDataStoreFactory,\n\tNamedFluidDataStoreRegistryEntry,\n} from \"@fluidframework/runtime-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport { tagCodeArtifacts, UsageError } from \"@fluidframework/telemetry-utils\";\nimport { IAgentScheduler, IAgentSchedulerEvents } from \"./agent\";\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 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\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\tassert(\n\t\t\t\tthis.runtime.objectsRoutingContext.isAttached,\n\t\t\t\t0x11c /* \"Detached object routing context\" */,\n\t\t\t);\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.runtime.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 * @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"]}
@@ -2,9 +2,9 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { TypedEventEmitter } from "@fluidframework/common-utils";
6
- import { IFluidHandle, IRequest } from "@fluidframework/core-interfaces";
7
- import { FluidDataStoreRuntime, ISharedObjectRegistry } from "@fluidframework/datastore";
5
+ import { TypedEventEmitter } from "@fluid-internal/client-utils";
6
+ import { IFluidHandle } from "@fluidframework/core-interfaces";
7
+ import { FluidDataStoreRuntime } from "@fluidframework/datastore";
8
8
  import { ConsensusRegisterCollection } from "@fluidframework/register-collection";
9
9
  import { IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions";
10
10
  import { IFluidDataStoreContext, IFluidDataStoreFactory, NamedFluidDataStoreRegistryEntry } from "@fluidframework/runtime-definitions";
@@ -15,6 +15,7 @@ export declare class AgentScheduler extends TypedEventEmitter<IAgentSchedulerEve
15
15
  private readonly consensusRegisterCollection;
16
16
  static load(runtime: IFluidDataStoreRuntime, context: IFluidDataStoreContext, existing: boolean): Promise<AgentScheduler>;
17
17
  get IAgentScheduler(): this;
18
+ get IFluidLoadable(): this;
18
19
  private get clientId();
19
20
  private readonly registeredTasks;
20
21
  private readonly locallyRunnableTasks;
@@ -23,7 +24,7 @@ export declare class AgentScheduler extends TypedEventEmitter<IAgentSchedulerEve
23
24
  constructor(runtime: IFluidDataStoreRuntime, context: IFluidDataStoreContext, consensusRegisterCollection: ConsensusRegisterCollection<string | null>);
24
25
  get handle(): IFluidHandle<this>;
25
26
  register(...taskUrls: string[]): Promise<void>;
26
- pick(taskId: string, worker: () => Promise<void>): Promise<void>;
27
+ pick(taskUrl: string, worker: () => Promise<void>): Promise<void>;
27
28
  release(...taskUrls: string[]): Promise<void>;
28
29
  pickedTasks(): string[];
29
30
  private registerCore;
@@ -39,18 +40,15 @@ export declare class AgentScheduler extends TypedEventEmitter<IAgentSchedulerEve
39
40
  private clearRunningTasks;
40
41
  private sendErrorEvent;
41
42
  }
42
- declare class AgentSchedulerRuntime extends FluidDataStoreRuntime {
43
- private readonly agentSchedulerP;
44
- constructor(dataStoreContext: IFluidDataStoreContext, sharedObjectRegistry: ISharedObjectRegistry, existing: boolean);
45
- request(request: IRequest): Promise<import("@fluidframework/core-interfaces").IResponse>;
46
- }
43
+ /**
44
+ * @alpha
45
+ */
47
46
  export declare class AgentSchedulerFactory implements IFluidDataStoreFactory {
48
47
  static readonly type = "_scheduler";
49
48
  readonly type = "_scheduler";
50
49
  get IFluidDataStoreFactory(): this;
51
50
  static get registryEntry(): NamedFluidDataStoreRegistryEntry;
52
- static createChildInstance(parentContext: IFluidDataStoreContext): Promise<AgentScheduler>;
53
- instantiateDataStore(context: IFluidDataStoreContext, existing: boolean): Promise<AgentSchedulerRuntime>;
51
+ static createChildInstance(parentContext: IFluidDataStoreContext): Promise<IAgentScheduler>;
52
+ instantiateDataStore(context: IFluidDataStoreContext, existing: boolean): Promise<FluidDataStoreRuntime>;
54
53
  }
55
- export {};
56
54
  //# sourceMappingURL=scheduler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAU,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EACH,YAAY,EACZ,QAAQ,EACX,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACH,qBAAqB,EAErB,qBAAqB,EACxB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAmB,MAAM,uCAAuC,CAAC;AAChG,OAAO,EACH,sBAAsB,EACtB,sBAAsB,EACtB,gCAAgC,EACnC,MAAM,qCAAqC,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AA4BjE,qBAAa,cAAe,SAAQ,iBAAiB,CAAC,qBAAqB,CAAE,YAAW,eAAe;IAmD/F,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,2BAA2B;WApD5B,IAAI,CAAC,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,OAAO;IAqB5G,IAAW,eAAe,SAAmB;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;gBAGxB,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,EAC/B,2BAA2B,EAAE,2BAA2B,CAAC,MAAM,GAAG,IAAI,CAAC;IAM5F,IAAW,MAAM,uBAEhB;IAEY,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBhE,OAAO,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBnD,WAAW,IAAI,MAAM,EAAE;YAIhB,YAAY;YAkBZ,WAAW;YAYX,UAAU;IASxB,OAAO,CAAC,eAAe;YAIT,SAAS;IAIvB,OAAO,CAAC,UAAU;IAiElB,OAAO,CAAC,iBAAiB;YAcX,gBAAgB;IAyB9B,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,cAAc;CAGzB;AAED,cAAM,qBAAsB,SAAQ,qBAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0B;gBAEtD,gBAAgB,EAAE,sBAAsB,EACxC,oBAAoB,EAAE,qBAAqB,EAC3C,QAAQ,EAAE,OAAO;IAKR,OAAO,CAAC,OAAO,EAAE,QAAQ;CAUzC;AAED,qBAAa,qBAAsB,YAAW,sBAAsB;IAChE,gBAAuB,IAAI,gBAAgB;IAC3C,SAAgB,IAAI,gBAA8B;IAElD,IAAW,sBAAsB,SAAmB;IAEpD,WAAkB,aAAa,IAAI,gCAAgC,CAElE;WAEmB,mBAAmB,CAAC,aAAa,EAAE,sBAAsB,GAAG,OAAO,CAAC,cAAc,CAAC;IAM1F,oBAAoB,CAAC,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,OAAO;CASvF"}
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,EAAe,YAAY,EAAY,MAAM,iCAAiC,CAAC;AACtF,OAAO,EACN,qBAAqB,EAGrB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,sBAAsB,EAAmB,MAAM,uCAAuC,CAAC;AAChG,OAAO,EACN,sBAAsB,EACtB,sBAAsB,EACtB,gCAAgC,EAChC,MAAM,qCAAqC,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AA4BjE,qBAAa,cACZ,SAAQ,iBAAiB,CAAC,qBAAqB,CAC/C,YAAW,eAAe;IAgEzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,2BAA2B;WAhEzB,IAAI,CACvB,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,sBAAsB,EAC/B,QAAQ,EAAE,OAAO;IAyBlB,IAAW,eAAe,SAEzB;IACD,IAAW,cAAc,SAExB;IAED,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;IAQzF,IAAW,MAAM,uBAEhB;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;IAiFlB,OAAO,CAAC,iBAAiB;YAcX,gBAAgB;IAuB9B,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,cAAc;CAGtB;AA6BD;;GAEG;AACH,qBAAa,qBAAsB,YAAW,sBAAsB;IACnE,gBAAuB,IAAI,gBAAgB;IAC3C,SAAgB,IAAI,gBAA8B;IAElD,IAAW,sBAAsB,SAEhC;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"}
@@ -5,11 +5,12 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.TaskSubscription = void 0;
8
- const common_utils_1 = require("@fluidframework/common-utils");
8
+ const client_utils_1 = require("@fluid-internal/client-utils");
9
9
  /**
10
10
  * TaskSubscription works with an AgentScheduler to make it easier to monitor a specific task ownership.
11
+ * @alpha
11
12
  */
12
- class TaskSubscription extends common_utils_1.TypedEventEmitter {
13
+ class TaskSubscription extends client_utils_1.TypedEventEmitter {
13
14
  /**
14
15
  * @param agentScheduler - The AgentScheduler that will be subscribed against
15
16
  * @param taskId - The string ID of the task to subscribe against
@@ -58,4 +59,4 @@ class TaskSubscription extends common_utils_1.TypedEventEmitter {
58
59
  }
59
60
  }
60
61
  exports.TaskSubscription = TaskSubscription;
61
- //# sourceMappingURL=taskSubscription.js.map
62
+ //# sourceMappingURL=taskSubscription.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taskSubscription.cjs","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,+DAAiE;AAWjE;;;GAGG;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;gBAC5B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;aACrB;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,OAAe,EAAE,EAAE;YACjD,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE;gBAC5B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;aACtB;QACF,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,OAAe,EAAE,EAAE;YAC7C,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE;gBAC5B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;aACtB;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;YACrB,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;SACvB;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 { IEvent } from \"@fluidframework/core-interfaces\";\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { IAgentScheduler } from \"./agent\";\n\n/**\n * Events emitted by {@link TaskSubscription}.\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 * @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"]}
@@ -2,14 +2,19 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { IEvent } from "@fluidframework/common-definitions";
6
- import { TypedEventEmitter } from "@fluidframework/common-utils";
5
+ import { IEvent } from "@fluidframework/core-interfaces";
6
+ import { TypedEventEmitter } from "@fluid-internal/client-utils";
7
7
  import { IAgentScheduler } from "./agent";
8
+ /**
9
+ * Events emitted by {@link TaskSubscription}.
10
+ * @alpha
11
+ */
8
12
  export interface ITaskSubscriptionEvents extends IEvent {
9
13
  (event: "gotTask" | "lostTask", listener: () => void): any;
10
14
  }
11
15
  /**
12
16
  * TaskSubscription works with an AgentScheduler to make it easier to monitor a specific task ownership.
17
+ * @alpha
13
18
  */
14
19
  export declare class TaskSubscription extends TypedEventEmitter<ITaskSubscriptionEvents> {
15
20
  private readonly agentScheduler;
@@ -1 +1 @@
1
- {"version":3,"file":"taskSubscription.d.ts","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,WAAW,uBAAwB,SAAQ,MAAM;IACnD,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CACzD;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,iBAAiB,CAAC,uBAAuB,CAAC;IAOhE,OAAO,CAAC,QAAQ,CAAC,cAAc;aAAmC,MAAM,EAAE,MAAM;IAN5F,OAAO,CAAC,UAAU,CAAkB;IAEpC;;;OAGG;gBAC0B,cAAc,EAAE,eAAe,EAAkB,MAAM,EAAE,MAAM;IAmB5F;;;OAGG;IACI,QAAQ;IAIf;;;OAGG;IACI,SAAS;CAUnB"}
1
+ {"version":3,"file":"taskSubscription.d.ts","sourceRoot":"","sources":["../src/taskSubscription.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C;;;GAGG;AACH,MAAM,WAAW,uBAAwB,SAAQ,MAAM;IACtD,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,OAAE;CACtD;AAED;;;GAGG;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;IAIf;;;OAGG;IACI,SAAS;CAUhB"}