extra-pool 0.1.3 → 0.1.5

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 CHANGED
@@ -38,7 +38,8 @@ interface IPoolOptions<T> {
38
38
  }
39
39
 
40
40
  class Pool<T> {
41
- get size(): number
41
+ readonly capacity: number
42
+ readonly size: number
42
43
 
43
44
  constructor(options: IPoolOptions<T>)
44
45
 
package/lib/index.d.ts CHANGED
@@ -1 +1 @@
1
- export * from './pool';
1
+ export * from './pool.js';
package/lib/index.js CHANGED
@@ -1,18 +1,2 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./pool"), exports);
1
+ export * from './pool.js';
18
2
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAsB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA"}
package/lib/instance.d.ts CHANGED
@@ -1,21 +1,23 @@
1
- import { Awaitable } from '@blackglory/prelude';
2
- import { Deferred } from 'extra-promise';
1
+ import { Awaitable, NonEmptyArray } from '@blackglory/prelude';
3
2
  export declare enum InstanceState {
4
- Creating = "creating",
5
- Idle = "idle",
6
- Using = "using",
7
- Destroying = "destroying",
8
- Destroyed = "destroyed"
3
+ Created = 0,
4
+ Initializing = 1,
5
+ Idle = 2,
6
+ Busy = 3,
7
+ Destroying = 4,
8
+ Destroyed = 5
9
9
  }
10
10
  export declare class Instance<T> {
11
+ #private;
12
+ private createInstance;
11
13
  private destroyInstance?;
12
14
  private fsm;
13
- private _users;
14
- readonly _instance: Deferred<T>;
15
+ private deferredCreateInstance;
16
+ private deferredDestroyInstance;
15
17
  get users(): number;
18
+ get state(): InstanceState;
16
19
  constructor(createInstance: () => Awaitable<T>, destroyInstance?: ((value: T) => Awaitable<void>) | undefined);
17
- waitForCreated(): Promise<void>;
18
- getState(): InstanceState;
19
20
  use<U>(fn: (instance: T) => Awaitable<U>): Promise<U>;
20
21
  destroy(): Promise<void>;
22
+ waitForState<States extends NonEmptyArray<InstanceState>>(...states: States): Promise<States[number]>;
21
23
  }
package/lib/instance.js CHANGED
@@ -1,28 +1,43 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Instance = exports.InstanceState = void 0;
4
- const prelude_1 = require("@blackglory/prelude");
5
- const extra_promise_1 = require("extra-promise");
6
- const extra_fsm_1 = require("extra-fsm");
7
- const rxjs_1 = require("rxjs");
8
- const operators_1 = require("rxjs/operators");
9
- var InstanceState;
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
7
+ if (kind === "m") throw new TypeError("Private method is not writable");
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
+ };
12
+ var _Instance_users;
13
+ import { pass } from '@blackglory/prelude';
14
+ import { ObservableFiniteStateMachine } from 'extra-fsm';
15
+ import { Deferred } from 'extra-promise';
16
+ import { firstValueFrom } from 'rxjs';
17
+ import { filter, map } from 'rxjs/operators';
18
+ export var InstanceState;
10
19
  (function (InstanceState) {
11
- InstanceState["Creating"] = "creating";
12
- InstanceState["Idle"] = "idle";
13
- InstanceState["Using"] = "using";
14
- InstanceState["Destroying"] = "destroying";
15
- InstanceState["Destroyed"] = "destroyed";
16
- })(InstanceState = exports.InstanceState || (exports.InstanceState = {}));
20
+ InstanceState[InstanceState["Created"] = 0] = "Created";
21
+ InstanceState[InstanceState["Initializing"] = 1] = "Initializing";
22
+ InstanceState[InstanceState["Idle"] = 2] = "Idle";
23
+ InstanceState[InstanceState["Busy"] = 3] = "Busy";
24
+ InstanceState[InstanceState["Destroying"] = 4] = "Destroying";
25
+ InstanceState[InstanceState["Destroyed"] = 5] = "Destroyed";
26
+ })(InstanceState || (InstanceState = {}));
17
27
  const instanceSchema = {
18
- [InstanceState.Creating]: {
19
- created: InstanceState.Idle
28
+ [InstanceState.Created]: {
29
+ init: InstanceState.Initializing,
30
+ destroy: InstanceState.Destroyed
31
+ },
32
+ [InstanceState.Initializing]: {
33
+ inited: InstanceState.Idle,
34
+ fail: InstanceState.Created
20
35
  },
21
36
  [InstanceState.Idle]: {
22
- use: InstanceState.Using,
37
+ use: InstanceState.Busy,
23
38
  destroy: InstanceState.Destroying
24
39
  },
25
- [InstanceState.Using]: {
40
+ [InstanceState.Busy]: {
26
41
  idle: InstanceState.Idle
27
42
  },
28
43
  [InstanceState.Destroying]: {
@@ -30,69 +45,139 @@ const instanceSchema = {
30
45
  },
31
46
  [InstanceState.Destroyed]: {}
32
47
  };
33
- class Instance {
48
+ export class Instance {
34
49
  get users() {
35
- return this._users;
50
+ return __classPrivateFieldGet(this, _Instance_users, "f");
51
+ }
52
+ get state() {
53
+ return this.fsm.state;
36
54
  }
37
55
  constructor(createInstance, destroyInstance) {
56
+ this.createInstance = createInstance;
38
57
  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);
42
- (0, prelude_1.go)(async () => {
43
- try {
44
- const instance = await createInstance();
45
- this.fsm.send('created');
46
- this._instance.resolve(instance);
47
- }
48
- catch (e) {
49
- this._instance.reject(e);
50
- }
51
- });
52
- }
53
- async waitForCreated() {
54
- await this._instance;
55
- }
56
- getState() {
57
- return this.fsm.state;
58
+ this.fsm = new ObservableFiniteStateMachine(instanceSchema, InstanceState.Created);
59
+ this.deferredCreateInstance = createDeferred();
60
+ this.deferredDestroyInstance = createDeferred();
61
+ _Instance_users.set(this, 0);
58
62
  }
59
63
  async use(fn) {
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');
64
+ const self = this;
65
+ switch (this.fsm.state) {
66
+ case InstanceState.Created: {
67
+ addUser();
68
+ try {
69
+ this.fsm.send('init');
70
+ let instance;
71
+ try {
72
+ instance = await this.createInstance();
73
+ this.deferredCreateInstance.resolve(instance);
74
+ this.fsm.send('inited');
75
+ }
76
+ catch (e) {
77
+ this.deferredCreateInstance.reject(e);
78
+ this.deferredCreateInstance = createDeferred();
79
+ this.fsm.send('fail');
80
+ throw e;
81
+ }
82
+ this.fsm.send('use');
83
+ return await fn(instance);
84
+ }
85
+ finally {
86
+ removeUser();
87
+ }
88
+ }
89
+ case InstanceState.Initializing: {
90
+ addUser();
91
+ try {
92
+ const instance = await this.deferredCreateInstance;
93
+ return await fn(instance);
94
+ }
95
+ finally {
96
+ removeUser();
97
+ }
98
+ }
99
+ case InstanceState.Idle: {
100
+ addUser();
101
+ try {
102
+ this.fsm.send('use');
103
+ const instance = await this.deferredCreateInstance;
104
+ return await fn(instance);
105
+ }
106
+ finally {
107
+ removeUser();
108
+ }
109
+ }
110
+ case InstanceState.Busy: {
111
+ addUser();
112
+ try {
113
+ const instance = await this.deferredCreateInstance;
114
+ return await fn(instance);
115
+ }
116
+ finally {
117
+ removeUser();
118
+ }
119
+ }
120
+ case InstanceState.Destroying:
121
+ case InstanceState.Destroyed: throw new Error('The instance is not available');
122
+ default: throw new Error(`Unhandled state`);
68
123
  }
69
- (0, prelude_1.assert)(this.fsm.state === InstanceState.Using, 'The instance state should be using');
70
- const instance = await this._instance;
71
- try {
72
- const result = await fn(instance);
73
- return result;
124
+ function addUser() {
125
+ var _a, _b;
126
+ __classPrivateFieldSet(_a = self, _Instance_users, (_b = __classPrivateFieldGet(_a, _Instance_users, "f"), _b++, _b), "f");
74
127
  }
75
- finally {
76
- if ((--this._users) === 0) {
77
- this.fsm.send('idle');
128
+ function removeUser() {
129
+ var _a, _b;
130
+ if ((__classPrivateFieldSet(_a = self, _Instance_users, (_b = __classPrivateFieldGet(_a, _Instance_users, "f"), --_b), "f")) === 0) {
131
+ if (self.fsm.can('idle'))
132
+ self.fsm.send('idle');
78
133
  }
79
134
  }
80
135
  }
81
136
  async destroy() {
82
137
  var _a;
83
- if (this.fsm.state === InstanceState.Creating ||
84
- this.fsm.state === InstanceState.Using) {
85
- await (0, rxjs_1.firstValueFrom)(this.fsm.observeStateChanges().pipe((0, operators_1.filter)(state => state.newState === InstanceState.Idle)));
86
- }
87
- if (this.fsm.state === InstanceState.Idle) {
88
- this.fsm.send('destroy');
89
- await ((_a = this.destroyInstance) === null || _a === void 0 ? void 0 : _a.call(this, await this._instance));
90
- this.fsm.send('destroyed');
91
- }
92
- else if (this.fsm.state === InstanceState.Destroying) {
93
- await (0, rxjs_1.firstValueFrom)(this.fsm.observeStateChanges().pipe((0, operators_1.filter)(state => state.newState === InstanceState.Destroyed)));
138
+ switch (this.fsm.state) {
139
+ case InstanceState.Created: {
140
+ this.fsm.send('destroy');
141
+ return;
142
+ }
143
+ case InstanceState.Initializing: {
144
+ await this.waitForState(InstanceState.Idle, InstanceState.Created);
145
+ return await this.destroy();
146
+ }
147
+ case InstanceState.Idle: {
148
+ this.fsm.send('destroy');
149
+ const instance = await this.deferredCreateInstance;
150
+ try {
151
+ await ((_a = this.destroyInstance) === null || _a === void 0 ? void 0 : _a.call(this, instance));
152
+ }
153
+ catch (e) {
154
+ this.deferredDestroyInstance.reject(e);
155
+ throw e;
156
+ }
157
+ this.fsm.send('destroyed');
158
+ this.deferredDestroyInstance.resolve();
159
+ return;
160
+ }
161
+ case InstanceState.Busy: {
162
+ await this.waitForState(InstanceState.Idle);
163
+ return await this.destroy();
164
+ }
165
+ case InstanceState.Destroying: {
166
+ await this.deferredDestroyInstance;
167
+ return;
168
+ }
169
+ case InstanceState.Destroyed: return;
170
+ default: throw new Error(`Unhandled state`);
94
171
  }
95
172
  }
173
+ async waitForState(...states) {
174
+ return await firstValueFrom(this.fsm.observeStateChanges().pipe(map(change => change.newState), filter(newState => states.includes(newState))));
175
+ }
176
+ }
177
+ _Instance_users = new WeakMap();
178
+ function createDeferred() {
179
+ const deferred = new Deferred();
180
+ Promise.resolve(deferred).catch(pass);
181
+ return deferred;
96
182
  }
97
- exports.Instance = Instance;
98
183
  //# sourceMappingURL=instance.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"instance.js","sourceRoot":"","sources":["../src/instance.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instance.js","sourceRoot":"","sources":["../src/instance.ts"],"names":[],"mappings":"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"}
package/lib/pool.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { CustomError } from '@blackglory/errors';
2
- import { Awaitable } from '@blackglory/prelude';
1
+ import { Awaitable, CustomError } from '@blackglory/prelude';
3
2
  interface IPoolOptions<T> {
4
3
  create: () => Awaitable<T>;
5
4
  destroy?: (value: T) => Awaitable<void>;
@@ -9,15 +8,16 @@ interface IPoolOptions<T> {
9
8
  concurrencyPerInstance?: number;
10
9
  }
11
10
  export declare class Pool<T> {
12
- private createInstance;
13
- private destroyInstance?;
14
- private fsm;
15
- private waitingUsers;
16
- private items;
17
- private maxInstances;
18
- private minInstances;
19
- private idleTimeout;
20
- private concurrencyPerInstance;
11
+ private readonly createInstance;
12
+ private readonly destroyInstance?;
13
+ private readonly fsm;
14
+ private readonly waitingUsers;
15
+ private readonly items;
16
+ private readonly maxInstances;
17
+ private readonly minInstances;
18
+ private readonly idleTimeout;
19
+ private readonly concurrencyPerInstance;
20
+ get capacity(): number;
21
21
  get size(): number;
22
22
  constructor(options: IPoolOptions<T>);
23
23
  use<U>(fn: (instance: T) => Awaitable<U>): Promise<U>;
package/lib/pool.js CHANGED
@@ -1,19 +1,15 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UnavailablePool = exports.Pool = void 0;
4
- const errors_1 = require("@blackglory/errors");
5
- const prelude_1 = require("@blackglory/prelude");
6
- const structures_1 = require("@blackglory/structures");
7
- const extra_fsm_1 = require("extra-fsm");
8
- const extra_promise_1 = require("extra-promise");
9
- const iterable_operator_1 = require("iterable-operator");
10
- const extra_timers_1 = require("extra-timers");
11
- const instance_1 = require("./instance");
1
+ import { go, CustomError, isntEmptyArray, assert } from '@blackglory/prelude';
2
+ import { Queue } from '@blackglory/structures';
3
+ import { FiniteStateMachine } from 'extra-fsm';
4
+ import { Deferred, each } from 'extra-promise';
5
+ import { toArray, filter } from 'iterable-operator';
6
+ import { setTimeout } from 'extra-timers';
7
+ import { Instance } from './instance.js';
12
8
  var PoolState;
13
9
  (function (PoolState) {
14
- PoolState["Running"] = "running";
15
- PoolState["Destroying"] = "destroying";
16
- PoolState["Destroyed"] = "destroyed";
10
+ PoolState[PoolState["Running"] = 0] = "Running";
11
+ PoolState[PoolState["Destroying"] = 1] = "Destroying";
12
+ PoolState[PoolState["Destroyed"] = 2] = "Destroyed";
17
13
  })(PoolState || (PoolState = {}));
18
14
  const poolSchema = {
19
15
  [PoolState.Running]: {
@@ -24,14 +20,17 @@ const poolSchema = {
24
20
  },
25
21
  [PoolState.Destroyed]: {}
26
22
  };
27
- class Pool {
23
+ export class Pool {
24
+ get capacity() {
25
+ return this.maxInstances;
26
+ }
28
27
  get size() {
29
28
  return this.items.size;
30
29
  }
31
30
  constructor(options) {
32
31
  var _a, _b, _c, _d;
33
- this.fsm = new extra_fsm_1.FiniteStateMachine(poolSchema, PoolState.Running);
34
- this.waitingUsers = new structures_1.Queue();
32
+ this.fsm = new FiniteStateMachine(poolSchema, PoolState.Running);
33
+ this.waitingUsers = new Queue();
35
34
  this.items = new Set();
36
35
  this.createInstance = options.create;
37
36
  this.destroyInstance = options.destroy;
@@ -41,17 +40,15 @@ class Pool {
41
40
  this.concurrencyPerInstance = (_d = options.concurrencyPerInstance) !== null && _d !== void 0 ? _d : 1;
42
41
  }
43
42
  async use(fn) {
43
+ assert(this.fsm.matches(PoolState.Running), 'The pool is not available');
44
44
  const self = this;
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) {
45
+ const item = go(() => {
46
+ const candidateItems = toArray(filter(this.items, item => item.instance.users < this.concurrencyPerInstance));
47
+ if (isntEmptyArray(candidateItems)) {
48
48
  return candidateItems.reduce((previous, current) => {
49
- if (current.instance.users < previous.instance.users) {
50
- return current;
51
- }
52
- else {
53
- return previous;
54
- }
49
+ return current.instance.users < previous.instance.users
50
+ ? current
51
+ : previous;
55
52
  });
56
53
  }
57
54
  });
@@ -60,13 +57,13 @@ class Pool {
60
57
  }
61
58
  else {
62
59
  if (this.items.size < this.maxInstances) {
63
- const instance = new instance_1.Instance(this.createInstance, this.destroyInstance);
60
+ const instance = new Instance(this.createInstance, this.destroyInstance);
64
61
  const item = { instance };
65
62
  this.items.add(item);
66
63
  return await useItem(item);
67
64
  }
68
65
  else {
69
- const waitingUser = new extra_promise_1.Deferred();
66
+ const waitingUser = new Deferred();
70
67
  this.waitingUsers.enqueue(waitingUser);
71
68
  const item = await waitingUser;
72
69
  return await useItem(item);
@@ -89,7 +86,7 @@ class Pool {
89
86
  if (item.instance.users === 0 &&
90
87
  self.items.size > self.minInstances) {
91
88
  if (self.idleTimeout > 0) {
92
- item.cancelScheduledDeletion = (0, extra_timers_1.setTimeout)(self.idleTimeout, deleteInstance);
89
+ item.cancelScheduledDeletion = setTimeout(self.idleTimeout, deleteInstance);
93
90
  }
94
91
  else {
95
92
  await deleteInstance();
@@ -105,19 +102,15 @@ class Pool {
105
102
  }
106
103
  async destroy() {
107
104
  this.fsm.send('destroy');
108
- for (const item of this.items) {
109
- await item.instance.destroy();
110
- }
105
+ await each(this.items, item => item.instance.destroy());
111
106
  this.items.clear();
112
- let deferred;
113
- while (deferred = this.waitingUsers.dequeue()) {
114
- deferred.reject(new UnavailablePool());
107
+ let waitingUser;
108
+ while (waitingUser = this.waitingUsers.dequeue()) {
109
+ waitingUser.reject(new UnavailablePool());
115
110
  }
116
111
  this.fsm.send('destroyed');
117
112
  }
118
113
  }
119
- exports.Pool = Pool;
120
- class UnavailablePool extends errors_1.CustomError {
114
+ export class UnavailablePool extends CustomError {
121
115
  }
122
- exports.UnavailablePool = UnavailablePool;
123
116
  //# sourceMappingURL=pool.js.map
package/lib/pool.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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"}
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",
3
+ "version": "0.1.5",
4
4
  "description": "A library that helps you create object/thread/connection pools",
5
5
  "keywords": [
6
6
  "pool",
@@ -12,57 +12,57 @@
12
12
  "lib",
13
13
  "src"
14
14
  ],
15
+ "type": "module",
15
16
  "main": "lib/index.js",
16
17
  "types": "lib/index.d.ts",
17
18
  "sideEffects": false,
19
+ "engines": {
20
+ "node": ">=22"
21
+ },
18
22
  "repository": "git@github.com:BlackGlory/extra-pool.git",
19
23
  "author": "BlackGlory <woshenmedoubuzhidao@blackglory.me>",
20
24
  "license": "MIT",
21
25
  "scripts": {
22
- "deduplicate": "yarn-deduplicate",
26
+ "prepare": "ts-patch install -s",
23
27
  "lint": "eslint --ext .js,.jsx,.ts,.tsx --quiet src __tests__",
24
- "test": "jest --runInBand --config jest.config.js",
25
- "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
26
- "test:coverage": "jest --coverage --config jest.config.js",
27
- "prepublishOnly": "run-s clean build",
28
+ "test": "vitest run",
29
+ "prepublishOnly": "run-s prepare clean build",
28
30
  "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",
31
+ "build": "tsc --project tsconfig.build.json",
32
32
  "release": "standard-version"
33
33
  },
34
34
  "husky": {
35
35
  "hooks": {
36
- "pre-commit": "run-s lint build test",
36
+ "pre-commit": "run-s prepare lint build test",
37
37
  "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
38
38
  }
39
39
  },
40
40
  "devDependencies": {
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",
41
+ "@commitlint/cli": "^20.4.2",
42
+ "@commitlint/config-conventional": "^20.4.2",
43
+ "@eslint/js": "^10.0.1",
44
+ "eslint": "^10.0.2",
47
45
  "husky": "^4.3.8",
48
- "jest": "^29.3.1",
49
46
  "npm-run-all": "^4.1.5",
50
- "rimraf": "^3.0.2",
47
+ "return-style": "^4.0.0",
48
+ "rimraf": "^6.1.3",
51
49
  "standard-version": "^9.5.0",
52
- "ts-jest": "^29.0.3",
53
- "tscpaths": "^0.0.9",
54
- "tslib": "^2.4.1",
55
- "typescript": "^4.9.3",
56
- "yarn-deduplicate": "^6.0.0"
50
+ "ts-patch": "^3.3.0",
51
+ "tslib": "^2.8.1",
52
+ "typescript": "^5.9.3",
53
+ "typescript-eslint": "^8.56.1",
54
+ "typescript-transform-paths": "^3.5.6",
55
+ "vite": "^7.3.1",
56
+ "vite-tsconfig-paths": "^6.1.1",
57
+ "vitest": "^4.0.18"
57
58
  },
58
59
  "dependencies": {
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",
64
- "extra-timers": "^0.2.5",
65
- "iterable-operator": "^2.5.0",
66
- "rxjs": "^7.5.7"
60
+ "@blackglory/prelude": "^0.4.0",
61
+ "@blackglory/structures": "^0.14.12",
62
+ "extra-fsm": "^0.2.1",
63
+ "extra-promise": "^7.1.1",
64
+ "extra-timers": "^0.3.0",
65
+ "iterable-operator": "^6.0.0",
66
+ "rxjs": "^7.8.2"
67
67
  }
68
68
  }
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export * from './pool'
1
+ export * from './pool.js'
package/src/instance.ts CHANGED
@@ -1,33 +1,41 @@
1
- import { go, assert, Awaitable } from '@blackglory/prelude'
1
+ import { Awaitable, NonEmptyArray, pass } from '@blackglory/prelude'
2
+ import { ObservableFiniteStateMachine, IFiniteStateMachineSchema } from 'extra-fsm'
2
3
  import { Deferred } from 'extra-promise'
3
- import { ObservableFiniteStateMachine } from 'extra-fsm'
4
4
  import { firstValueFrom } from 'rxjs'
5
- import { filter } from 'rxjs/operators'
5
+ import { filter, map } from 'rxjs/operators'
6
6
 
7
7
  export enum InstanceState {
8
- Creating = 'creating'
9
- , Idle = 'idle'
10
- , Using = 'using'
11
- , Destroying = 'destroying'
12
- , Destroyed = 'destroyed'
8
+ Created
9
+ , Initializing
10
+ , Idle
11
+ , Busy
12
+ , Destroying
13
+ , Destroyed
13
14
  }
14
15
 
15
16
  type InstanceEvent =
16
- | 'created'
17
+ | 'init'
18
+ | 'inited'
19
+ | 'fail'
17
20
  | 'use'
18
21
  | 'idle'
19
22
  | 'destroy'
20
23
  | 'destroyed'
21
24
 
22
- const instanceSchema = {
23
- [InstanceState.Creating]: {
24
- created: InstanceState.Idle
25
+ const instanceSchema: IFiniteStateMachineSchema<InstanceState, InstanceEvent> = {
26
+ [InstanceState.Created]: {
27
+ init: InstanceState.Initializing
28
+ , destroy: InstanceState.Destroyed
29
+ }
30
+ , [InstanceState.Initializing]: {
31
+ inited: InstanceState.Idle
32
+ , fail: InstanceState.Created
25
33
  }
26
34
  , [InstanceState.Idle]: {
27
- use: InstanceState.Using
35
+ use: InstanceState.Busy
28
36
  , destroy: InstanceState.Destroying
29
37
  }
30
- , [InstanceState.Using]: {
38
+ , [InstanceState.Busy]: {
31
39
  idle: InstanceState.Idle
32
40
  }
33
41
  , [InstanceState.Destroying]: {
@@ -37,97 +45,180 @@ const instanceSchema = {
37
45
  }
38
46
 
39
47
  export class Instance<T> {
40
- private fsm: ObservableFiniteStateMachine<InstanceState, InstanceEvent>
41
- private _users = 0
42
- readonly _instance: Deferred<T>
43
-
48
+ private fsm: ObservableFiniteStateMachine<
49
+ InstanceState
50
+ , InstanceEvent
51
+ > = new ObservableFiniteStateMachine(
52
+ instanceSchema
53
+ , InstanceState.Created
54
+ )
55
+
56
+ private deferredCreateInstance: Deferred<T> = createDeferred()
57
+ private deferredDestroyInstance: Deferred<void> = createDeferred()
58
+
59
+ #users = 0
44
60
  get users(): number {
45
- return this._users
61
+ return this.#users
62
+ }
63
+
64
+ get state(): InstanceState {
65
+ return this.fsm.state
46
66
  }
47
67
 
48
68
  constructor(
49
- createInstance: () => Awaitable<T>
69
+ private createInstance: () => Awaitable<T>
50
70
  , 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
- )
71
+ ) {}
72
+
73
+ async use<U>(fn: (instance: T) => Awaitable<U>): Promise<U> {
74
+ const self = this
75
+
76
+ switch (this.fsm.state) {
77
+ case InstanceState.Created: {
78
+ addUser()
79
+
80
+ try {
81
+ this.fsm.send('init')
82
+
83
+ let instance: T
84
+ try {
85
+ instance = await this.createInstance()
86
+ this.deferredCreateInstance.resolve(instance)
87
+
88
+ this.fsm.send('inited')
89
+ } catch (e) {
90
+ this.deferredCreateInstance.reject(e)
91
+ this.deferredCreateInstance = createDeferred()
57
92
 
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)
93
+ this.fsm.send('fail')
94
+
95
+ throw e
96
+ }
97
+
98
+ this.fsm.send('use')
99
+ return await fn(instance)
100
+ } finally {
101
+ removeUser()
102
+ }
65
103
  }
66
- })
67
- }
104
+ case InstanceState.Initializing: {
105
+ addUser()
68
106
 
69
- async waitForCreated(): Promise<void> {
70
- await this._instance
71
- }
107
+ try {
108
+ const instance = await this.deferredCreateInstance
72
109
 
73
- getState(): InstanceState {
74
- return this.fsm.state
75
- }
110
+ // 由导致初始化的调用将负责状态转换.
76
111
 
77
- async use<U>(fn: (instance: T) => Awaitable<U>): Promise<U> {
78
- // 不要尝试将此处的代码改编成switch管道, 很难正确编写.
112
+ return await fn(instance)
113
+ } finally {
114
+ removeUser()
115
+ }
116
+ }
117
+ case InstanceState.Idle: {
118
+ addUser()
79
119
 
80
- assert(
81
- this.fsm.state !== InstanceState.Destroying &&
82
- this.fsm.state !== InstanceState.Destroyed
83
- , 'The instance is not available'
84
- )
120
+ try {
121
+ this.fsm.send('use')
122
+
123
+ const instance = await this.deferredCreateInstance
124
+
125
+ return await fn(instance)
126
+ } finally {
127
+ removeUser()
128
+ }
129
+ }
130
+ case InstanceState.Busy: {
131
+ addUser()
85
132
 
86
- this._users++
133
+ try {
134
+ const instance = await this.deferredCreateInstance
87
135
 
88
- if (this.fsm.state === InstanceState.Creating) {
89
- await this._instance
136
+ return await fn(instance)
137
+ } finally {
138
+ removeUser()
139
+ }
140
+ }
141
+ case InstanceState.Destroying:
142
+ case InstanceState.Destroyed: throw new Error('The instance is not available')
143
+ default: throw new Error(`Unhandled state`)
90
144
  }
91
145
 
92
- if (this.fsm.state === InstanceState.Idle) {
93
- this.fsm.send('use')
146
+ function addUser(): void {
147
+ self.#users++
94
148
  }
95
149
 
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')
150
+ function removeUser(): void {
151
+ if ((--self.#users) === 0) {
152
+ if (self.fsm.can('idle')) self.fsm.send('idle')
104
153
  }
105
154
  }
106
155
  }
107
156
 
108
157
  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)
158
+ switch (this.fsm.state) {
159
+ case InstanceState.Created: {
160
+ this.fsm.send('destroy')
161
+
162
+ return
163
+ }
164
+ case InstanceState.Initializing: {
165
+ await this.waitForState(
166
+ InstanceState.Idle
167
+ , InstanceState.Created
116
168
  )
117
- )
169
+
170
+ return await this.destroy()
171
+ }
172
+ case InstanceState.Idle: {
173
+ this.fsm.send('destroy')
174
+
175
+ const instance = await this.deferredCreateInstance
176
+
177
+ try {
178
+ await this.destroyInstance?.(instance)
179
+ } catch (e) {
180
+ // 如果destroy过程中出错, 之后的所有destroy调用都会抛出相同错误.
181
+ // 此实例的状态将停留在Destroying, 这是预期行为.
182
+ this.deferredDestroyInstance.reject(e)
183
+
184
+ throw e
185
+ }
186
+
187
+ this.fsm.send('destroyed')
188
+
189
+ this.deferredDestroyInstance.resolve()
190
+
191
+ return
192
+ }
193
+ case InstanceState.Busy: {
194
+ await this.waitForState(InstanceState.Idle)
195
+
196
+ return await this.destroy()
197
+ }
198
+ case InstanceState.Destroying: {
199
+ await this.deferredDestroyInstance
200
+
201
+ return
202
+ }
203
+ case InstanceState.Destroyed: return
204
+ default: throw new Error(`Unhandled state`)
118
205
  }
206
+ }
119
207
 
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
- )
208
+ async waitForState<States extends NonEmptyArray<InstanceState>>(
209
+ ...states: States
210
+ ): Promise<States[number]> {
211
+ return await firstValueFrom(
212
+ this.fsm.observeStateChanges().pipe(
213
+ map(change => change.newState)
214
+ , filter(newState => states.includes(newState))
130
215
  )
131
- }
216
+ )
132
217
  }
133
218
  }
219
+
220
+ function createDeferred<T>(): Deferred<T> {
221
+ const deferred = new Deferred<T>()
222
+ Promise.resolve(deferred).catch(pass)
223
+ return deferred
224
+ }
package/src/pool.ts CHANGED
@@ -1,11 +1,10 @@
1
- import { CustomError } from '@blackglory/errors'
2
- import { go, Awaitable } from '@blackglory/prelude'
1
+ import { go, Awaitable, CustomError, isntEmptyArray, assert } from '@blackglory/prelude'
3
2
  import { Queue } from '@blackglory/structures'
4
- import { FiniteStateMachine } from 'extra-fsm'
5
- import { Deferred } from 'extra-promise'
3
+ import { FiniteStateMachine, IFiniteStateMachineSchema } from 'extra-fsm'
4
+ import { Deferred, each } from 'extra-promise'
6
5
  import { toArray, filter } from 'iterable-operator'
7
6
  import { setTimeout } from 'extra-timers'
8
- import { Instance, InstanceState } from './instance'
7
+ import { Instance } from './instance.js'
9
8
 
10
9
  interface IPoolOptions<T> {
11
10
  create: () => Awaitable<T>
@@ -51,16 +50,16 @@ interface IPoolItem<T> {
51
50
  }
52
51
 
53
52
  enum PoolState {
54
- Running = 'running'
55
- , Destroying = 'destroying'
56
- , Destroyed = 'destroyed'
53
+ Running
54
+ , Destroying
55
+ , Destroyed
57
56
  }
58
57
 
59
58
  type PoolEvent =
60
59
  | 'destroy'
61
60
  | 'destroyed'
62
61
 
63
- const poolSchema = {
62
+ const poolSchema: IFiniteStateMachineSchema<PoolState, PoolEvent> = {
64
63
  [PoolState.Running]: {
65
64
  destroy: PoolState.Destroying
66
65
  }
@@ -71,18 +70,25 @@ const poolSchema = {
71
70
  }
72
71
 
73
72
  export class Pool<T> {
74
- private createInstance: () => Awaitable<T>
75
- private destroyInstance?: (value: T) => Awaitable<void>
76
- private fsm = new FiniteStateMachine<PoolState, PoolEvent>(
73
+ private readonly createInstance: () => Awaitable<T>
74
+ private readonly destroyInstance?: (value: T) => Awaitable<void>
75
+ private readonly fsm: FiniteStateMachine<
76
+ PoolState
77
+ , PoolEvent
78
+ > = new FiniteStateMachine(
77
79
  poolSchema
78
80
  , PoolState.Running
79
81
  )
80
- private waitingUsers: Queue<Deferred<IPoolItem<T>>> = new Queue()
81
- private items: Set<IPoolItem<T>> = new Set()
82
- private maxInstances: number
83
- private minInstances: number
84
- private idleTimeout: number
85
- private concurrencyPerInstance: number
82
+ private readonly waitingUsers: Queue<Deferred<IPoolItem<T>>> = new Queue()
83
+ private readonly items: Set<IPoolItem<T>> = new Set()
84
+ private readonly maxInstances: number
85
+ private readonly minInstances: number
86
+ private readonly idleTimeout: number
87
+ private readonly concurrencyPerInstance: number
88
+
89
+ get capacity(): number {
90
+ return this.maxInstances
91
+ }
86
92
 
87
93
  get size(): number {
88
94
  return this.items.size
@@ -102,6 +108,8 @@ export class Pool<T> {
102
108
  * 函数的使用者应该尊重阻塞, 否则会意外制造大量非必要的Promise.
103
109
  */
104
110
  async use<U>(fn: (instance: T) => Awaitable<U>): Promise<U> {
111
+ assert(this.fsm.matches(PoolState.Running), 'The pool is not available')
112
+
105
113
  const self = this
106
114
 
107
115
  const item = go(() => {
@@ -110,13 +118,12 @@ export class Pool<T> {
110
118
  , item => item.instance.users < this.concurrencyPerInstance
111
119
  ))
112
120
 
113
- if (candidateItems.length) {
121
+ if (isntEmptyArray(candidateItems)) {
122
+ // 找到负载最低(用户量最少)的项目.
114
123
  return candidateItems.reduce((previous, current) => {
115
- if (current.instance.users < previous.instance.users) {
116
- return current
117
- } else {
118
- return previous
119
- }
124
+ return current.instance.users < previous.instance.users
125
+ ? current
126
+ : previous
120
127
  })
121
128
  }
122
129
  })
@@ -177,14 +184,12 @@ export class Pool<T> {
177
184
  async destroy(): Promise<void> {
178
185
  this.fsm.send('destroy')
179
186
 
180
- for (const item of this.items) {
181
- await item.instance.destroy()
182
- }
187
+ await each(this.items, item => item.instance.destroy())
183
188
  this.items.clear()
184
189
 
185
- let deferred: Deferred<IPoolItem<T>> | undefined
186
- while (deferred = this.waitingUsers.dequeue()) {
187
- deferred.reject(new UnavailablePool())
190
+ let waitingUser: Deferred<IPoolItem<T>> | undefined
191
+ while (waitingUser = this.waitingUsers.dequeue()) {
192
+ waitingUser.reject(new UnavailablePool())
188
193
  }
189
194
 
190
195
  this.fsm.send('destroyed')