extra-pool 0.1.0 → 0.1.2
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/README.md +2 -1
- package/lib/index.js.map +1 -0
- package/lib/{es2015/instance.d.ts → instance.d.ts} +5 -3
- package/lib/{es2018/instance.js → instance.js} +35 -19
- package/lib/instance.js.map +1 -0
- package/lib/{es2015/pool.d.ts → pool.d.ts} +5 -3
- package/lib/{es2018/pool.js → pool.js} +46 -35
- package/lib/pool.js.map +1 -0
- package/package.json +26 -41
- package/src/index.ts +1 -0
- package/src/instance.ts +133 -0
- package/src/pool.ts +194 -0
- package/dist/es2015/index.min.mjs +0 -2
- package/dist/es2015/index.min.mjs.map +0 -1
- package/dist/es2015/index.mjs +0 -16672
- package/dist/es2015/index.mjs.map +0 -1
- package/dist/es2015/index.umd.js +0 -16683
- package/dist/es2015/index.umd.js.map +0 -1
- package/dist/es2015/index.umd.min.js +0 -2
- package/dist/es2015/index.umd.min.js.map +0 -1
- package/dist/es2018/index.min.mjs +0 -2
- package/dist/es2018/index.min.mjs.map +0 -1
- package/dist/es2018/index.mjs +0 -16648
- package/dist/es2018/index.mjs.map +0 -1
- package/dist/es2018/index.umd.js +0 -16659
- package/dist/es2018/index.umd.js.map +0 -1
- package/dist/es2018/index.umd.min.js +0 -2
- package/dist/es2018/index.umd.min.js.map +0 -1
- package/lib/es2015/index.js.map +0 -1
- package/lib/es2015/instance.js +0 -97
- package/lib/es2015/instance.js.map +0 -1
- package/lib/es2015/pool.js +0 -129
- package/lib/es2015/pool.js.map +0 -1
- package/lib/es2018/index.d.ts +0 -1
- package/lib/es2018/index.js +0 -18
- package/lib/es2018/index.js.map +0 -1
- package/lib/es2018/instance.d.ts +0 -19
- package/lib/es2018/instance.js.map +0 -1
- package/lib/es2018/pool.d.ts +0 -26
- package/lib/es2018/pool.js.map +0 -1
- /package/lib/{es2015/index.d.ts → index.d.ts} +0 -0
- /package/lib/{es2015/index.js → index.js} +0 -0
package/README.md
CHANGED
|
@@ -31,9 +31,10 @@ await dbConnectionPool.destroy()
|
|
|
31
31
|
interface IPoolOptions<T> {
|
|
32
32
|
create: () => Awaitable<T>
|
|
33
33
|
destroy?: (instance: T) => Awaitable<void>
|
|
34
|
-
maxInstances
|
|
34
|
+
maxInstances?: number
|
|
35
35
|
minInstances?: number = 0
|
|
36
36
|
idleTimeout?: number = 0
|
|
37
|
+
concurrencyPerInstance? = 1
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
class Pool<T> {
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAsB"}
|
|
@@ -8,10 +8,12 @@ export declare enum InstanceState {
|
|
|
8
8
|
Destroyed = "destroyed"
|
|
9
9
|
}
|
|
10
10
|
export declare class Instance<T> {
|
|
11
|
-
private
|
|
11
|
+
private destroyInstance?;
|
|
12
12
|
private fsm;
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
private _users;
|
|
14
|
+
readonly _instance: Deferred<T>;
|
|
15
|
+
get users(): number;
|
|
16
|
+
constructor(createInstance: () => Awaitable<T>, destroyInstance?: ((value: T) => Awaitable<void>) | undefined);
|
|
15
17
|
waitForCreated(): Promise<void>;
|
|
16
18
|
getState(): InstanceState;
|
|
17
19
|
use<U>(fn: (instance: T) => Awaitable<U>): Promise<U>;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Instance = exports.InstanceState = void 0;
|
|
4
4
|
const prelude_1 = require("@blackglory/prelude");
|
|
5
5
|
const extra_promise_1 = require("extra-promise");
|
|
6
|
-
const
|
|
6
|
+
const extra_fsm_1 = require("extra-fsm");
|
|
7
7
|
const rxjs_1 = require("rxjs");
|
|
8
8
|
const operators_1 = require("rxjs/operators");
|
|
9
9
|
var InstanceState;
|
|
@@ -23,7 +23,7 @@ const instanceSchema = {
|
|
|
23
23
|
destroy: InstanceState.Destroying
|
|
24
24
|
},
|
|
25
25
|
[InstanceState.Using]: {
|
|
26
|
-
|
|
26
|
+
idle: InstanceState.Idle
|
|
27
27
|
},
|
|
28
28
|
[InstanceState.Destroying]: {
|
|
29
29
|
destroyed: InstanceState.Destroyed
|
|
@@ -31,49 +31,65 @@ const instanceSchema = {
|
|
|
31
31
|
[InstanceState.Destroyed]: {}
|
|
32
32
|
};
|
|
33
33
|
class Instance {
|
|
34
|
-
|
|
35
|
-
this.
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
get users() {
|
|
35
|
+
return this._users;
|
|
36
|
+
}
|
|
37
|
+
constructor(createInstance, destroyInstance) {
|
|
38
|
+
this.destroyInstance = destroyInstance;
|
|
39
|
+
this._users = 0;
|
|
40
|
+
this._instance = new extra_promise_1.Deferred();
|
|
41
|
+
this.fsm = new extra_fsm_1.ObservableFiniteStateMachine(instanceSchema, InstanceState.Creating);
|
|
38
42
|
(0, prelude_1.go)(async () => {
|
|
39
43
|
try {
|
|
40
|
-
const
|
|
41
|
-
this._value.resolve(val);
|
|
44
|
+
const instance = await createInstance();
|
|
42
45
|
this.fsm.send('created');
|
|
46
|
+
this._instance.resolve(instance);
|
|
43
47
|
}
|
|
44
48
|
catch (e) {
|
|
45
|
-
this.
|
|
49
|
+
this._instance.reject(e);
|
|
46
50
|
}
|
|
47
51
|
});
|
|
48
52
|
}
|
|
49
53
|
async waitForCreated() {
|
|
50
|
-
await this.
|
|
54
|
+
await this._instance;
|
|
51
55
|
}
|
|
52
56
|
getState() {
|
|
53
57
|
return this.fsm.state;
|
|
54
58
|
}
|
|
55
59
|
async use(fn) {
|
|
56
|
-
this.fsm.
|
|
57
|
-
|
|
60
|
+
(0, prelude_1.assert)(this.fsm.state !== InstanceState.Destroying &&
|
|
61
|
+
this.fsm.state !== InstanceState.Destroyed, 'The instance is not available');
|
|
62
|
+
this._users++;
|
|
63
|
+
if (this.fsm.state === InstanceState.Creating) {
|
|
64
|
+
await this._instance;
|
|
65
|
+
}
|
|
66
|
+
if (this.fsm.state === InstanceState.Idle) {
|
|
67
|
+
this.fsm.send('use');
|
|
68
|
+
}
|
|
69
|
+
(0, prelude_1.assert)(this.fsm.state === InstanceState.Using, 'The instance state should be using');
|
|
70
|
+
const instance = await this._instance;
|
|
58
71
|
try {
|
|
59
|
-
|
|
72
|
+
const result = await fn(instance);
|
|
73
|
+
return result;
|
|
60
74
|
}
|
|
61
75
|
finally {
|
|
62
|
-
this.
|
|
76
|
+
if ((--this._users) === 0) {
|
|
77
|
+
this.fsm.send('idle');
|
|
78
|
+
}
|
|
63
79
|
}
|
|
64
80
|
}
|
|
65
81
|
async destroy() {
|
|
66
82
|
var _a;
|
|
67
|
-
if (this.fsm.
|
|
68
|
-
this.fsm.
|
|
83
|
+
if (this.fsm.state === InstanceState.Creating ||
|
|
84
|
+
this.fsm.state === InstanceState.Using) {
|
|
69
85
|
await (0, rxjs_1.firstValueFrom)(this.fsm.observeStateChanges().pipe((0, operators_1.filter)(state => state.newState === InstanceState.Idle)));
|
|
70
86
|
}
|
|
71
|
-
if (this.fsm.
|
|
87
|
+
if (this.fsm.state === InstanceState.Idle) {
|
|
72
88
|
this.fsm.send('destroy');
|
|
73
|
-
await ((_a = this.
|
|
89
|
+
await ((_a = this.destroyInstance) === null || _a === void 0 ? void 0 : _a.call(this, await this._instance));
|
|
74
90
|
this.fsm.send('destroyed');
|
|
75
91
|
}
|
|
76
|
-
else if (this.fsm.
|
|
92
|
+
else if (this.fsm.state === InstanceState.Destroying) {
|
|
77
93
|
await (0, rxjs_1.firstValueFrom)(this.fsm.observeStateChanges().pipe((0, operators_1.filter)(state => state.newState === InstanceState.Destroyed)));
|
|
78
94
|
}
|
|
79
95
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance.js","sourceRoot":"","sources":["../src/instance.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,16 +6,18 @@ interface IPoolOptions<T> {
|
|
|
6
6
|
maxInstances?: number;
|
|
7
7
|
minInstances?: number;
|
|
8
8
|
idleTimeout?: number;
|
|
9
|
+
concurrencyPerInstance?: number;
|
|
9
10
|
}
|
|
10
11
|
export declare class Pool<T> {
|
|
11
|
-
private
|
|
12
|
-
private
|
|
12
|
+
private createInstance;
|
|
13
|
+
private destroyInstance?;
|
|
13
14
|
private fsm;
|
|
15
|
+
private waitingUsers;
|
|
14
16
|
private items;
|
|
15
|
-
private userDeferredQueue;
|
|
16
17
|
private maxInstances;
|
|
17
18
|
private minInstances;
|
|
18
19
|
private idleTimeout;
|
|
20
|
+
private concurrencyPerInstance;
|
|
19
21
|
get size(): number;
|
|
20
22
|
constructor(options: IPoolOptions<T>);
|
|
21
23
|
use<U>(fn: (instance: T) => Awaitable<U>): Promise<U>;
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.UnavailablePool = exports.Pool = void 0;
|
|
4
4
|
const errors_1 = require("@blackglory/errors");
|
|
5
|
+
const prelude_1 = require("@blackglory/prelude");
|
|
5
6
|
const structures_1 = require("@blackglory/structures");
|
|
7
|
+
const extra_fsm_1 = require("extra-fsm");
|
|
6
8
|
const extra_promise_1 = require("extra-promise");
|
|
7
9
|
const iterable_operator_1 = require("iterable-operator");
|
|
8
|
-
const instance_1 = require("./instance");
|
|
9
10
|
const extra_timers_1 = require("extra-timers");
|
|
11
|
+
const instance_1 = require("./instance");
|
|
10
12
|
var PoolState;
|
|
11
13
|
(function (PoolState) {
|
|
12
14
|
PoolState["Running"] = "running";
|
|
@@ -23,70 +25,79 @@ const poolSchema = {
|
|
|
23
25
|
[PoolState.Destroyed]: {}
|
|
24
26
|
};
|
|
25
27
|
class Pool {
|
|
28
|
+
get size() {
|
|
29
|
+
return this.items.size;
|
|
30
|
+
}
|
|
26
31
|
constructor(options) {
|
|
27
|
-
var _a, _b, _c;
|
|
28
|
-
this.fsm = new
|
|
32
|
+
var _a, _b, _c, _d;
|
|
33
|
+
this.fsm = new extra_fsm_1.FiniteStateMachine(poolSchema, PoolState.Running);
|
|
34
|
+
this.waitingUsers = new structures_1.Queue();
|
|
29
35
|
this.items = new Set();
|
|
30
|
-
this.
|
|
31
|
-
this.
|
|
32
|
-
this.destroyValue = options.destroy;
|
|
36
|
+
this.createInstance = options.create;
|
|
37
|
+
this.destroyInstance = options.destroy;
|
|
33
38
|
this.maxInstances = (_a = options.maxInstances) !== null && _a !== void 0 ? _a : Infinity;
|
|
34
39
|
this.minInstances = (_b = options.minInstances) !== null && _b !== void 0 ? _b : 0;
|
|
35
40
|
this.idleTimeout = (_c = options.idleTimeout) !== null && _c !== void 0 ? _c : 0;
|
|
36
|
-
|
|
37
|
-
get size() {
|
|
38
|
-
return this.items.size;
|
|
41
|
+
this.concurrencyPerInstance = (_d = options.concurrencyPerInstance) !== null && _d !== void 0 ? _d : 1;
|
|
39
42
|
}
|
|
40
43
|
async use(fn) {
|
|
41
44
|
const self = this;
|
|
42
|
-
const item = (0,
|
|
45
|
+
const item = (0, prelude_1.go)(() => {
|
|
46
|
+
const candidateItems = (0, iterable_operator_1.toArray)((0, iterable_operator_1.filter)(this.items, item => item.instance.users < this.concurrencyPerInstance));
|
|
47
|
+
if (candidateItems.length) {
|
|
48
|
+
return candidateItems.reduce((previous, current) => {
|
|
49
|
+
if (current.instance.users < previous.instance.users) {
|
|
50
|
+
return current;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
return previous;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
});
|
|
43
58
|
if (item) {
|
|
44
|
-
return await
|
|
59
|
+
return await useItem(item);
|
|
45
60
|
}
|
|
46
61
|
else {
|
|
47
62
|
if (this.items.size < this.maxInstances) {
|
|
48
|
-
const instance = new instance_1.Instance(this.
|
|
49
|
-
const item = {
|
|
50
|
-
instance,
|
|
51
|
-
using: true
|
|
52
|
-
};
|
|
63
|
+
const instance = new instance_1.Instance(this.createInstance, this.destroyInstance);
|
|
64
|
+
const item = { instance };
|
|
53
65
|
this.items.add(item);
|
|
54
|
-
return await
|
|
66
|
+
return await useItem(item);
|
|
55
67
|
}
|
|
56
68
|
else {
|
|
57
|
-
const
|
|
58
|
-
this.
|
|
59
|
-
const item = await
|
|
60
|
-
return await
|
|
69
|
+
const waitingUser = new extra_promise_1.Deferred();
|
|
70
|
+
this.waitingUsers.enqueue(waitingUser);
|
|
71
|
+
const item = await waitingUser;
|
|
72
|
+
return await useItem(item);
|
|
61
73
|
}
|
|
62
74
|
}
|
|
63
|
-
async function
|
|
64
|
-
item.
|
|
65
|
-
|
|
66
|
-
item.
|
|
67
|
-
delete item.cancelDeletion;
|
|
75
|
+
async function useItem(item) {
|
|
76
|
+
if (item.cancelScheduledDeletion) {
|
|
77
|
+
item.cancelScheduledDeletion();
|
|
78
|
+
delete item.cancelScheduledDeletion;
|
|
68
79
|
}
|
|
69
|
-
await item.instance.waitForCreated();
|
|
70
80
|
try {
|
|
71
81
|
return await item.instance.use(fn);
|
|
72
82
|
}
|
|
73
83
|
finally {
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
const waitingUser = self.waitingUsers.dequeue();
|
|
85
|
+
if (waitingUser) {
|
|
86
|
+
waitingUser.resolve(item);
|
|
76
87
|
}
|
|
77
88
|
else {
|
|
78
|
-
item.
|
|
79
|
-
|
|
89
|
+
if (item.instance.users === 0 &&
|
|
90
|
+
self.items.size > self.minInstances) {
|
|
80
91
|
if (self.idleTimeout > 0) {
|
|
81
|
-
item.
|
|
92
|
+
item.cancelScheduledDeletion = (0, extra_timers_1.setTimeout)(self.idleTimeout, deleteInstance);
|
|
82
93
|
}
|
|
83
94
|
else {
|
|
84
|
-
await
|
|
95
|
+
await deleteInstance();
|
|
85
96
|
}
|
|
86
97
|
}
|
|
87
98
|
}
|
|
88
99
|
}
|
|
89
|
-
async function
|
|
100
|
+
async function deleteInstance() {
|
|
90
101
|
self.items.delete(item);
|
|
91
102
|
await item.instance.destroy();
|
|
92
103
|
}
|
|
@@ -99,7 +110,7 @@ class Pool {
|
|
|
99
110
|
}
|
|
100
111
|
this.items.clear();
|
|
101
112
|
let deferred;
|
|
102
|
-
while (deferred = this.
|
|
113
|
+
while (deferred = this.waitingUsers.dequeue()) {
|
|
103
114
|
deferred.reject(new UnavailablePool());
|
|
104
115
|
}
|
|
105
116
|
this.fsm.send('destroyed');
|
package/lib/pool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "extra-pool",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "A library that helps you create object/thread/connection pools",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pool",
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
],
|
|
11
11
|
"files": [
|
|
12
12
|
"lib",
|
|
13
|
-
"
|
|
13
|
+
"src"
|
|
14
14
|
],
|
|
15
|
-
"main": "lib/
|
|
16
|
-
"types": "lib/
|
|
15
|
+
"main": "lib/index.js",
|
|
16
|
+
"types": "lib/index.d.ts",
|
|
17
17
|
"sideEffects": false,
|
|
18
18
|
"repository": "git@github.com:BlackGlory/extra-pool.git",
|
|
19
19
|
"author": "BlackGlory <woshenmedoubuzhidao@blackglory.me>",
|
|
@@ -24,18 +24,11 @@
|
|
|
24
24
|
"test": "jest --runInBand --config jest.config.js",
|
|
25
25
|
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
|
|
26
26
|
"test:coverage": "jest --coverage --config jest.config.js",
|
|
27
|
-
"prepublishOnly": "run-s clean build
|
|
28
|
-
"clean": "
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"build": "
|
|
32
|
-
"build:es2015": "run-s build:es2015:*",
|
|
33
|
-
"build:es2015:compile": "tsc --project tsconfig.build.json --module commonjs --target es2015 --outDir lib/es2015",
|
|
34
|
-
"build:es2015:patch": "tscpaths -p tsconfig.build.json -s ./src -o ./lib/es2015",
|
|
35
|
-
"build:es2018": "run-s build:es2018:*",
|
|
36
|
-
"build:es2018:compile": "tsc --project tsconfig.build.json --module commonjs --target es2018 --outDir lib/es2018",
|
|
37
|
-
"build:es2018:patch": "tscpaths -p tsconfig.build.json -s ./src -o ./lib/es2018",
|
|
38
|
-
"bundle": "rollup --config rollup.config.js",
|
|
27
|
+
"prepublishOnly": "run-s clean build",
|
|
28
|
+
"clean": "rimraf lib",
|
|
29
|
+
"build": "run-s build:*",
|
|
30
|
+
"build:compile": "tsc --project tsconfig.build.json --module commonjs --target es2018 --outDir lib",
|
|
31
|
+
"build:patch": "tscpaths -p tsconfig.build.json -s ./src -o ./lib",
|
|
39
32
|
"release": "standard-version"
|
|
40
33
|
},
|
|
41
34
|
"husky": {
|
|
@@ -45,39 +38,31 @@
|
|
|
45
38
|
}
|
|
46
39
|
},
|
|
47
40
|
"devDependencies": {
|
|
48
|
-
"@
|
|
49
|
-
"@commitlint/
|
|
50
|
-
"@
|
|
51
|
-
"@
|
|
52
|
-
"@
|
|
53
|
-
"
|
|
54
|
-
"@rollup/plugin-replace": "^4.0.0",
|
|
55
|
-
"@rollup/plugin-typescript": "^8.4.0",
|
|
56
|
-
"@types/jest": "^27.4.1",
|
|
57
|
-
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
|
58
|
-
"@typescript-eslint/parser": "^5.35.1",
|
|
59
|
-
"eslint": "^8.22.0",
|
|
41
|
+
"@commitlint/cli": "^17.3.0",
|
|
42
|
+
"@commitlint/config-conventional": "^17.3.0",
|
|
43
|
+
"@types/jest": "^29.2.3",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^5.44.0",
|
|
45
|
+
"@typescript-eslint/parser": "^5.44.0",
|
|
46
|
+
"eslint": "^8.28.0",
|
|
60
47
|
"husky": "^4.3.8",
|
|
61
|
-
"jest": "^
|
|
48
|
+
"jest": "^29.3.1",
|
|
62
49
|
"npm-run-all": "^4.1.5",
|
|
63
50
|
"rimraf": "^3.0.2",
|
|
64
|
-
"rollup": "^2.78.1",
|
|
65
|
-
"rollup-plugin-analyzer": "^4.0.0",
|
|
66
|
-
"rollup-plugin-terser": "^7.0.2",
|
|
67
51
|
"standard-version": "^9.5.0",
|
|
68
|
-
"ts-jest": "^
|
|
52
|
+
"ts-jest": "^29.0.3",
|
|
69
53
|
"tscpaths": "^0.0.9",
|
|
70
|
-
"tslib": "^2.
|
|
71
|
-
"typescript": "^4.
|
|
54
|
+
"tslib": "^2.4.1",
|
|
55
|
+
"typescript": "^4.9.3",
|
|
72
56
|
"yarn-deduplicate": "^6.0.0"
|
|
73
57
|
},
|
|
74
58
|
"dependencies": {
|
|
75
|
-
"@blackglory/errors": "^2.
|
|
76
|
-
"@blackglory/prelude": "^0.1.
|
|
77
|
-
"@blackglory/structures": "^0.
|
|
78
|
-
"extra-
|
|
59
|
+
"@blackglory/errors": "^2.3.0",
|
|
60
|
+
"@blackglory/prelude": "^0.1.8",
|
|
61
|
+
"@blackglory/structures": "^0.11.4",
|
|
62
|
+
"extra-fsm": "^0.1.1",
|
|
63
|
+
"extra-promise": "^4.4.0",
|
|
79
64
|
"extra-timers": "^0.2.5",
|
|
80
|
-
"iterable-operator": "^
|
|
81
|
-
"rxjs": "^7.5.
|
|
65
|
+
"iterable-operator": "^2.5.0",
|
|
66
|
+
"rxjs": "^7.5.7"
|
|
82
67
|
}
|
|
83
68
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './pool'
|
package/src/instance.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { go, assert, Awaitable } from '@blackglory/prelude'
|
|
2
|
+
import { Deferred } from 'extra-promise'
|
|
3
|
+
import { ObservableFiniteStateMachine } from 'extra-fsm'
|
|
4
|
+
import { firstValueFrom } from 'rxjs'
|
|
5
|
+
import { filter } from 'rxjs/operators'
|
|
6
|
+
|
|
7
|
+
export enum InstanceState {
|
|
8
|
+
Creating = 'creating'
|
|
9
|
+
, Idle = 'idle'
|
|
10
|
+
, Using = 'using'
|
|
11
|
+
, Destroying = 'destroying'
|
|
12
|
+
, Destroyed = 'destroyed'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type InstanceEvent =
|
|
16
|
+
| 'created'
|
|
17
|
+
| 'use'
|
|
18
|
+
| 'idle'
|
|
19
|
+
| 'destroy'
|
|
20
|
+
| 'destroyed'
|
|
21
|
+
|
|
22
|
+
const instanceSchema = {
|
|
23
|
+
[InstanceState.Creating]: {
|
|
24
|
+
created: InstanceState.Idle
|
|
25
|
+
}
|
|
26
|
+
, [InstanceState.Idle]: {
|
|
27
|
+
use: InstanceState.Using
|
|
28
|
+
, destroy: InstanceState.Destroying
|
|
29
|
+
}
|
|
30
|
+
, [InstanceState.Using]: {
|
|
31
|
+
idle: InstanceState.Idle
|
|
32
|
+
}
|
|
33
|
+
, [InstanceState.Destroying]: {
|
|
34
|
+
destroyed: InstanceState.Destroyed
|
|
35
|
+
}
|
|
36
|
+
, [InstanceState.Destroyed]: {}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class Instance<T> {
|
|
40
|
+
private fsm: ObservableFiniteStateMachine<InstanceState, InstanceEvent>
|
|
41
|
+
private _users = 0
|
|
42
|
+
readonly _instance: Deferred<T>
|
|
43
|
+
|
|
44
|
+
get users(): number {
|
|
45
|
+
return this._users
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
constructor(
|
|
49
|
+
createInstance: () => Awaitable<T>
|
|
50
|
+
, private destroyInstance?: (value: T) => Awaitable<void>
|
|
51
|
+
) {
|
|
52
|
+
this._instance = new Deferred<T>()
|
|
53
|
+
this.fsm = new ObservableFiniteStateMachine<InstanceState, InstanceEvent>(
|
|
54
|
+
instanceSchema
|
|
55
|
+
, InstanceState.Creating
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
go(async () => {
|
|
59
|
+
try {
|
|
60
|
+
const instance = await createInstance()
|
|
61
|
+
this.fsm.send('created')
|
|
62
|
+
this._instance.resolve(instance)
|
|
63
|
+
} catch (e) {
|
|
64
|
+
this._instance.reject(e)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async waitForCreated(): Promise<void> {
|
|
70
|
+
await this._instance
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getState(): InstanceState {
|
|
74
|
+
return this.fsm.state
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async use<U>(fn: (instance: T) => Awaitable<U>): Promise<U> {
|
|
78
|
+
// 不要尝试将此处的代码改编成switch管道, 很难正确编写.
|
|
79
|
+
|
|
80
|
+
assert(
|
|
81
|
+
this.fsm.state !== InstanceState.Destroying &&
|
|
82
|
+
this.fsm.state !== InstanceState.Destroyed
|
|
83
|
+
, 'The instance is not available'
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
this._users++
|
|
87
|
+
|
|
88
|
+
if (this.fsm.state === InstanceState.Creating) {
|
|
89
|
+
await this._instance
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (this.fsm.state === InstanceState.Idle) {
|
|
93
|
+
this.fsm.send('use')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
assert(this.fsm.state === InstanceState.Using, 'The instance state should be using')
|
|
97
|
+
const instance = await this._instance
|
|
98
|
+
try {
|
|
99
|
+
const result = await fn(instance)
|
|
100
|
+
return result
|
|
101
|
+
} finally {
|
|
102
|
+
if ((--this._users) === 0) {
|
|
103
|
+
this.fsm.send('idle')
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async destroy(): Promise<void> {
|
|
109
|
+
if (
|
|
110
|
+
this.fsm.state === InstanceState.Creating ||
|
|
111
|
+
this.fsm.state === InstanceState.Using
|
|
112
|
+
) {
|
|
113
|
+
await firstValueFrom(
|
|
114
|
+
this.fsm.observeStateChanges().pipe(
|
|
115
|
+
filter(state => state.newState === InstanceState.Idle)
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (this.fsm.state === InstanceState.Idle) {
|
|
121
|
+
this.fsm.send('destroy')
|
|
122
|
+
// 如果destroyed过程报错, 则程序崩溃, 这是预期行为.
|
|
123
|
+
await this.destroyInstance?.(await this._instance)
|
|
124
|
+
this.fsm.send('destroyed')
|
|
125
|
+
} else if (this.fsm.state === InstanceState.Destroying) {
|
|
126
|
+
await firstValueFrom(
|
|
127
|
+
this.fsm.observeStateChanges().pipe(
|
|
128
|
+
filter(state => state.newState === InstanceState.Destroyed)
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|