Skip to content

Commit a0175b4

Browse files
authored
Add experimental TaskManager DDS (#5398)
This change adds a new DDS for the purpose of negotiating mutually exclusive task ownership amongst collaborators. It's under the @fluid-experimental namespace for now. It also updates the clicker example to use it, rather than the AgentScheduler.
1 parent 7080c1b commit a0175b4

19 files changed

+933
-14
lines changed

examples/data-objects/clicker/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"webpack:dev": "webpack --env.development"
3838
},
3939
"dependencies": {
40+
"@fluid-experimental/task-manager": "^0.36.0",
4041
"@fluidframework/aqueduct": "^0.36.0",
4142
"@fluidframework/common-definitions": "^0.19.1",
4243
"@fluidframework/core-interfaces": "^0.36.0",

examples/data-objects/clicker/src/index.tsx

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
* Licensed under the MIT License.
44
*/
55

6+
import { TaskManager } from "@fluid-experimental/task-manager";
67
import { DataObject, DataObjectFactory } from "@fluidframework/aqueduct";
78
import { IFluidHandle } from "@fluidframework/core-interfaces";
89
import { SharedCounter } from "@fluidframework/counter";
9-
import { IAgentScheduler } from "@fluidframework/runtime-definitions";
1010
import { IFluidHTMLView } from "@fluidframework/view-interfaces";
1111
import React from "react";
1212
import ReactDOM from "react-dom";
@@ -15,6 +15,9 @@ import { ClickerAgent } from "./agent";
1515
export const ClickerName = "Clicker";
1616

1717
const counterKey = "counter";
18+
const taskManagerKey = "taskManager";
19+
20+
const consoleLogTaskId = "ConsoleLog";
1821

1922
/**
2023
* Basic Clicker example using new interfaces and stock component classes.
@@ -23,19 +26,29 @@ export class Clicker extends DataObject implements IFluidHTMLView {
2326
public get IFluidHTMLView() { return this; }
2427

2528
private _counter: SharedCounter | undefined;
29+
private _taskManager: TaskManager | undefined;
2630

2731
/**
2832
* Do setup work here
2933
*/
3034
protected async initializingFirstTime() {
3135
const counter = SharedCounter.create(this.runtime);
3236
this.root.set(counterKey, counter.handle);
37+
const taskManager = TaskManager.create(this.runtime);
38+
this.root.set(taskManagerKey, taskManager.handle);
3339
}
3440

3541
protected async hasInitialized() {
3642
const counterHandle = this.root.get<IFluidHandle<SharedCounter>>(counterKey);
3743
this._counter = await counterHandle?.get();
38-
this.setupAgent();
44+
const taskManagerHandle = this.root.get<IFluidHandle<TaskManager>>(taskManagerKey);
45+
this._taskManager = await taskManagerHandle?.get();
46+
47+
if (this.runtime.connected) {
48+
this.setupAgent();
49+
} else {
50+
this.runtime.once("connected", () => { this.setupAgent(); });
51+
}
3952
}
4053

4154
// #region IFluidHTMLView
@@ -55,19 +68,12 @@ export class Clicker extends DataObject implements IFluidHTMLView {
5568
// #endregion IFluidHTMLView
5669

5770
public setupAgent() {
58-
const agentTaskId = "agent";
59-
const clickerAgent = new ClickerAgent(this.counter);
60-
61-
this.context.containerRuntime.request({ url: "/_scheduler" }).then(async (agentSchedulerResponse) => {
62-
if (agentSchedulerResponse.status === 404) {
63-
throw new Error("Agent scheduler not found");
64-
}
65-
const agentScheduler = agentSchedulerResponse.value as IAgentScheduler;
66-
await agentScheduler.pick(agentTaskId, async () => {
71+
this.taskManager.lockTask(consoleLogTaskId)
72+
.then(async () => {
6773
console.log(`Picked`);
74+
const clickerAgent = new ClickerAgent(this.counter);
6875
await clickerAgent.run();
69-
});
70-
}).catch((err) => { console.error(err); });
76+
}).catch((err) => { console.error(err); });
7177
}
7278

7379
private get counter() {
@@ -76,6 +82,13 @@ export class Clicker extends DataObject implements IFluidHTMLView {
7682
}
7783
return this._counter;
7884
}
85+
86+
private get taskManager() {
87+
if (this._taskManager === undefined) {
88+
throw new Error("TaskManager not initialized");
89+
}
90+
return this._taskManager;
91+
}
7992
}
8093

8194
// ----- REACT STUFF -----
@@ -120,7 +133,7 @@ class CounterReactView extends React.Component<CounterProps, CounterState> {
120133
export const ClickerInstantiationFactory = new DataObjectFactory(
121134
ClickerName,
122135
Clicker,
123-
[SharedCounter.getFactory()],
136+
[SharedCounter.getFactory(), TaskManager.getFactory()],
124137
{},
125138
);
126139

lerna-package-lock.json

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*!
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License.
4+
*/
5+
6+
module.exports = {
7+
"extends": [
8+
"@fluidframework/eslint-config-fluid/eslint7"
9+
],
10+
"parserOptions": {
11+
"project": ["./tsconfig.json", "./src/test/tsconfig.json"]
12+
},
13+
}

packages/dds/task-manager/.gitignore

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Compiled TypeScript and CSS
2+
dist
3+
lib
4+
5+
# Babel
6+
public/scripts/es5
7+
8+
# Logs
9+
logs
10+
*.log
11+
12+
# Runtime data
13+
pids
14+
*.pid
15+
*.seed
16+
17+
# Directory for instrumented libs generated by jscoverage/JSCover
18+
lib-cov
19+
20+
# Coverage directory used by tools like istanbul
21+
coverage
22+
23+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24+
.grunt
25+
.cache-loader
26+
27+
# node-waf configuration
28+
.lock-wscript
29+
30+
# Compiled binary addons (http://nodejs.org/api/addons.html)
31+
build/Release
32+
33+
# Dependency directory
34+
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
35+
node_modules
36+
37+
# Typings
38+
typings
39+
40+
# Debug log from npm
41+
npm-debug.log
42+
43+
# Code coverage
44+
nyc
45+
.nyc_output/
46+
47+
# Chart dependencies
48+
**/charts/*.tgz
49+
50+
# Generated modules
51+
intel_modules/
52+
temp_modules/

packages/dds/task-manager/.npmignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
nyc
2+
*.log
3+
**/*.tsbuildinfo
4+
src/test
5+
dist/test
6+
**/_api-extractor-temp/**

packages/dds/task-manager/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Copyright (c) Microsoft Corporation. All rights reserved.
2+
3+
MIT License
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

packages/dds/task-manager/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# @fluid-experimental/task-manager
2+
3+
Documentation available at https://fluidframework.com/apis/task-manager/.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3+
"extends": "@fluidframework/build-common/api-extractor-common.json"
4+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{
2+
"name": "@fluid-experimental/task-manager",
3+
"version": "0.36.0",
4+
"description": "Distributed data structure for queueing exclusive tasks",
5+
"homepage": "https://fluidframework.com",
6+
"repository": "https://github.com/microsoft/FluidFramework",
7+
"license": "MIT",
8+
"author": "Microsoft",
9+
"sideEffects": false,
10+
"main": "dist/index.js",
11+
"module": "lib/index.js",
12+
"types": "dist/index.d.ts",
13+
"scripts": {
14+
"build": "npm run build:genver && concurrently npm:build:compile npm:lint",
15+
"build:commonjs": "npm run tsc && npm run build:test",
16+
"build:compile": "concurrently npm:build:commonjs npm:build:esnext",
17+
"build:docs": "api-extractor run --local && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
18+
"build:esnext": "tsc --project ./tsconfig.esnext.json",
19+
"build:full": "npm run build",
20+
"build:full:compile": "npm run build:compile",
21+
"build:genver": "gen-version",
22+
"build:test": "tsc --project ./src/test/tsconfig.json",
23+
"clean": "rimraf dist lib *.tsbuildinfo *.build.log",
24+
"eslint": "eslint --format stylish src",
25+
"eslint:fix": "eslint --format stylish src --fix",
26+
"lint": "npm run eslint",
27+
"lint:fix": "npm run eslint:fix",
28+
"test": "npm run test:mocha",
29+
"test:coverage": "nyc npm test -- --reporter mocha-junit-reporter --reporter-options mochaFile=nyc/junit-report.xml",
30+
"test:mocha": "mocha --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
31+
"test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
32+
"tsc": "tsc",
33+
"tsfmt": "tsfmt --verify",
34+
"tsfmt:fix": "tsfmt --replace"
35+
},
36+
"nyc": {
37+
"all": true,
38+
"cache-dir": "nyc/.cache",
39+
"exclude": [
40+
"src/test/**/*.ts",
41+
"dist/test/**/*.js"
42+
],
43+
"exclude-after-remap": false,
44+
"include": [
45+
"src/**/*.ts",
46+
"dist/**/*.js"
47+
],
48+
"report-dir": "nyc/report",
49+
"reporter": [
50+
"cobertura",
51+
"html",
52+
"text"
53+
],
54+
"temp-directory": "nyc/.nyc_output"
55+
},
56+
"dependencies": {
57+
"@fluidframework/common-utils": "^0.28.0-0",
58+
"@fluidframework/core-interfaces": "^0.36.0",
59+
"@fluidframework/datastore-definitions": "^0.36.0",
60+
"@fluidframework/protocol-definitions": "^0.1021.0-0",
61+
"@fluidframework/shared-object-base": "^0.36.0",
62+
"assert": "^2.0.0",
63+
"debug": "^4.1.1"
64+
},
65+
"devDependencies": {
66+
"@fluid-internal/test-dds-utils": "^0.36.0",
67+
"@fluidframework/build-common": "^0.20.0",
68+
"@fluidframework/eslint-config-fluid": "^0.23.0",
69+
"@fluidframework/mocha-test-setup": "^0.36.0",
70+
"@fluidframework/test-runtime-utils": "^0.36.0",
71+
"@microsoft/api-extractor": "^7.13.1",
72+
"@types/assert": "^1.5.2",
73+
"@types/debug": "^4.1.5",
74+
"@types/mocha": "^5.2.5",
75+
"@types/node": "^10.17.24",
76+
"@typescript-eslint/eslint-plugin": "~4.14.0",
77+
"@typescript-eslint/parser": "~4.14.0",
78+
"concurrently": "^5.2.0",
79+
"copyfiles": "^2.1.0",
80+
"cross-env": "^7.0.2",
81+
"eslint": "~7.18.0",
82+
"eslint-plugin-eslint-comments": "~3.2.0",
83+
"eslint-plugin-import": "~2.22.1",
84+
"eslint-plugin-no-null": "~1.0.2",
85+
"eslint-plugin-prefer-arrow": "~1.2.2",
86+
"eslint-plugin-react": "~7.22.0",
87+
"eslint-plugin-unicorn": "~26.0.1",
88+
"mocha": "^8.1.1",
89+
"mocha-junit-reporter": "^1.18.0",
90+
"nyc": "^15.0.0",
91+
"rimraf": "^2.6.2",
92+
"typescript": "~4.1.3",
93+
"typescript-formatter": "7.1.0"
94+
}
95+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*!
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License.
4+
*/
5+
6+
export * from "./taskManager";
7+
export * from "./interfaces";

0 commit comments

Comments
 (0)