@adaptivestone/framework 5.0.0-beta.6 → 5.0.0-beta.8
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/CHANGELOG.md +10 -0
- package/jsconfig.json +1 -1
- package/models/Lock.js +107 -0
- package/package.json +1 -1
- package/server.d.ts +1 -1
- package/tests/setupVitest.js +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
### 5.0.0-beta.8
|
|
2
|
+
|
|
3
|
+
[UPDATE] update deps
|
|
4
|
+
[NEW] Lock model for workingwir locks via mongoDB
|
|
5
|
+
|
|
6
|
+
### 5.0.0-beta.7
|
|
7
|
+
|
|
8
|
+
[UPDATE] update deps
|
|
9
|
+
[UPDATE] change vitest shutdown behavior as mongo driver v6.13 change befaviur that affect us (MongoClient.close now closes any outstanding cursors)
|
|
10
|
+
|
|
1
11
|
### 5.0.0-beta.5
|
|
2
12
|
|
|
3
13
|
[BREAKING] remove minimist CLI parsing and replace it by commandArguments parser
|
package/jsconfig.json
CHANGED
package/models/Lock.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import AbstractModel from '../modules/AbstractModel.js';
|
|
2
|
+
|
|
3
|
+
class Lock extends AbstractModel {
|
|
4
|
+
initHooks() {
|
|
5
|
+
this.mongooseSchema.index({ expiredAt: 1 }, { expireAfterSeconds: 0 });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line class-methods-use-this
|
|
9
|
+
get modelSchema() {
|
|
10
|
+
return {
|
|
11
|
+
_id: { type: String, required: true },
|
|
12
|
+
expiredAt: {
|
|
13
|
+
type: Date,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* acquire lock based on lock name
|
|
20
|
+
* @param {string} name
|
|
21
|
+
* @param {number} [ttlSeconds=30]
|
|
22
|
+
* @returns {Promise<boolean>}
|
|
23
|
+
*/
|
|
24
|
+
static async acquireLock(name, ttlSeconds = 30) {
|
|
25
|
+
try {
|
|
26
|
+
await this.create({
|
|
27
|
+
_id: name,
|
|
28
|
+
expiredAt: new Date(Date.now() + ttlSeconds * 1000),
|
|
29
|
+
});
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error.code !== 11000) {
|
|
32
|
+
// not a duplicate leys
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* release lock based on lock name
|
|
42
|
+
* @param {string} name
|
|
43
|
+
* @returns {Promise<boolean>}
|
|
44
|
+
*/
|
|
45
|
+
static async releaseLock(name) {
|
|
46
|
+
const res = await this.deleteOne({ _id: name });
|
|
47
|
+
if (res.acknowledged && res.deletedCount) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* wait lock based on lock name
|
|
55
|
+
* @param {string} name
|
|
56
|
+
* @returns {Promise}
|
|
57
|
+
*/
|
|
58
|
+
static async waitForUnlock(name) {
|
|
59
|
+
const res = await this.findOne({ _id: name });
|
|
60
|
+
if (!res) {
|
|
61
|
+
return Promise.resolve();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
const stream = this.watch([
|
|
66
|
+
{ $match: { operationType: 'delete', 'documentKey._id': name } },
|
|
67
|
+
]);
|
|
68
|
+
stream.on('change', () => {
|
|
69
|
+
stream.close();
|
|
70
|
+
resolve();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* get lock remaining time based on lock name
|
|
77
|
+
* @param {string} name
|
|
78
|
+
* @returns {Promise<{ttl: number}>}
|
|
79
|
+
*/
|
|
80
|
+
static async getLockData(name) {
|
|
81
|
+
const res = await this.findOne({ _id: name });
|
|
82
|
+
if (!res) {
|
|
83
|
+
return { ttl: 0 };
|
|
84
|
+
}
|
|
85
|
+
return { ttl: res.expiredAt.getTime() - Date.now() };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* get lock remaining time based on lock name
|
|
90
|
+
* @param {string[]} names
|
|
91
|
+
* @returns {Promise<{name: string, ttl: number}[]>}
|
|
92
|
+
*/
|
|
93
|
+
static async getLocksData(names) {
|
|
94
|
+
const res = await this.find({ _id: { $in: names } });
|
|
95
|
+
const lockMap = new Map(res.map((lock) => [lock._id, lock]));
|
|
96
|
+
|
|
97
|
+
return names.map((name) => {
|
|
98
|
+
const lock = lockMap.get(name);
|
|
99
|
+
return {
|
|
100
|
+
name,
|
|
101
|
+
ttl: lock ? lock.expiredAt.getTime() - Date.now() : 0,
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default Lock;
|
package/package.json
CHANGED
package/server.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ declare class Server {
|
|
|
46
46
|
/**
|
|
47
47
|
* Start server (http + init all http ralated functions)
|
|
48
48
|
*/
|
|
49
|
-
startServer(callbackBefore404?: Promise<null>): Promise<null>;
|
|
49
|
+
startServer(callbackBefore404?: () => Promise<null>): Promise<null>;
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Do an initialization (config reading, etc)
|
package/tests/setupVitest.js
CHANGED
|
@@ -102,6 +102,11 @@ afterAll(async () => {
|
|
|
102
102
|
if (typeof global.testSetup.afterAll === 'function') {
|
|
103
103
|
await global.testSetup.afterAll();
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
try {
|
|
106
|
+
await mongoose.connection.db.dropDatabase(); // clean database after test
|
|
107
|
+
} catch {
|
|
108
|
+
// that ok. No mongoose connection
|
|
109
|
+
}
|
|
110
|
+
|
|
106
111
|
await mongoose.disconnect();
|
|
107
112
|
});
|