@lakutata/mutex 0.0.0-stage → 3.0.0-beta.0
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/LICENSE +23 -0
- package/README.md +212 -2
- package/dist/cjs/exports/Mutex.d.ts +18 -0
- package/dist/cjs/exports/Mutex.js +37 -0
- package/dist/cjs/mutex/Mutex.d.ts +265 -0
- package/dist/cjs/mutex/Mutex.js +403 -0
- package/dist/cjs/mutex/MutexLock.d.ts +91 -0
- package/dist/cjs/mutex/MutexLock.js +113 -0
- package/dist/cjs/mutex/Synchronized.d.ts +90 -0
- package/dist/cjs/mutex/Synchronized.js +93 -0
- package/dist/cjs/mutex/drivers/FileMutexDriver.d.ts +115 -0
- package/dist/cjs/mutex/drivers/FileMutexDriver.js +230 -0
- package/dist/cjs/mutex/drivers/MemoryMutexDriver.d.ts +60 -0
- package/dist/cjs/mutex/drivers/MemoryMutexDriver.js +95 -0
- package/dist/cjs/mutex/drivers/MutexDriver.d.ts +82 -0
- package/dist/cjs/mutex/drivers/MutexDriver.js +38 -0
- package/dist/cjs/mutex/drivers/MysqlMutexDriver.d.ts +135 -0
- package/dist/cjs/mutex/drivers/MysqlMutexDriver.js +244 -0
- package/dist/cjs/mutex/drivers/PostgresMutexDriver.d.ts +136 -0
- package/dist/cjs/mutex/drivers/PostgresMutexDriver.js +230 -0
- package/dist/cjs/mutex/drivers/RedisMutexDriver.d.ts +129 -0
- package/dist/cjs/mutex/drivers/RedisMutexDriver.js +180 -0
- package/dist/cjs/mutex/exceptions/MutexDriverException.d.ts +12 -0
- package/dist/cjs/mutex/exceptions/MutexDriverException.js +19 -0
- package/dist/cjs/mutex/exceptions/MutexDriverNotFoundException.d.ts +12 -0
- package/dist/cjs/mutex/exceptions/MutexDriverNotFoundException.js +19 -0
- package/dist/cjs/mutex/exceptions/MutexLostException.d.ts +13 -0
- package/dist/cjs/mutex/exceptions/MutexLostException.js +20 -0
- package/dist/cjs/mutex/exceptions/MutexTimeoutException.d.ts +16 -0
- package/dist/cjs/mutex/exceptions/MutexTimeoutException.js +23 -0
- package/dist/cjs/mutex/lib/LoadDriver.d.ts +6 -0
- package/dist/cjs/mutex/lib/LoadDriver.js +64 -0
- package/dist/cjs/mutex/lib/Names.d.ts +14 -0
- package/dist/cjs/mutex/lib/Names.js +26 -0
- package/dist/cjs/mutex/options/FileMutexOptions.d.ts +33 -0
- package/dist/cjs/mutex/options/FileMutexOptions.js +45 -0
- package/dist/cjs/mutex/options/MemoryMutexOptions.d.ts +27 -0
- package/dist/cjs/mutex/options/MemoryMutexOptions.js +41 -0
- package/dist/cjs/mutex/options/MysqlMutexOptions.d.ts +70 -0
- package/dist/cjs/mutex/options/MysqlMutexOptions.js +77 -0
- package/dist/cjs/mutex/options/PostgresMutexOptions.d.ts +83 -0
- package/dist/cjs/mutex/options/PostgresMutexOptions.js +89 -0
- package/dist/cjs/mutex/options/RedisMutexOptions.d.ts +71 -0
- package/dist/cjs/mutex/options/RedisMutexOptions.js +77 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/exports/Mutex.js +18 -0
- package/dist/esm/mutex/Mutex.js +397 -0
- package/dist/esm/mutex/MutexLock.js +109 -0
- package/dist/esm/mutex/Synchronized.js +89 -0
- package/dist/esm/mutex/drivers/FileMutexDriver.js +223 -0
- package/dist/esm/mutex/drivers/MemoryMutexDriver.js +91 -0
- package/dist/esm/mutex/drivers/MutexDriver.js +34 -0
- package/dist/esm/mutex/drivers/MysqlMutexDriver.js +240 -0
- package/dist/esm/mutex/drivers/PostgresMutexDriver.js +226 -0
- package/dist/esm/mutex/drivers/RedisMutexDriver.js +176 -0
- package/dist/esm/mutex/exceptions/MutexDriverException.js +15 -0
- package/dist/esm/mutex/exceptions/MutexDriverNotFoundException.js +15 -0
- package/dist/esm/mutex/exceptions/MutexLostException.js +16 -0
- package/dist/esm/mutex/exceptions/MutexTimeoutException.js +19 -0
- package/dist/esm/mutex/lib/LoadDriver.js +28 -0
- package/dist/esm/mutex/lib/Names.js +21 -0
- package/dist/esm/mutex/options/FileMutexOptions.js +41 -0
- package/dist/esm/mutex/options/MemoryMutexOptions.js +37 -0
- package/dist/esm/mutex/options/MysqlMutexOptions.js +73 -0
- package/dist/esm/mutex/options/PostgresMutexOptions.js +85 -0
- package/dist/esm/mutex/options/RedisMutexOptions.js +73 -0
- package/dist/types/exports/Mutex.d.ts +18 -0
- package/dist/types/mutex/Mutex.d.ts +265 -0
- package/dist/types/mutex/MutexLock.d.ts +91 -0
- package/dist/types/mutex/Synchronized.d.ts +90 -0
- package/dist/types/mutex/drivers/FileMutexDriver.d.ts +115 -0
- package/dist/types/mutex/drivers/MemoryMutexDriver.d.ts +60 -0
- package/dist/types/mutex/drivers/MutexDriver.d.ts +82 -0
- package/dist/types/mutex/drivers/MysqlMutexDriver.d.ts +135 -0
- package/dist/types/mutex/drivers/PostgresMutexDriver.d.ts +136 -0
- package/dist/types/mutex/drivers/RedisMutexDriver.d.ts +129 -0
- package/dist/types/mutex/exceptions/MutexDriverException.d.ts +12 -0
- package/dist/types/mutex/exceptions/MutexDriverNotFoundException.d.ts +12 -0
- package/dist/types/mutex/exceptions/MutexLostException.d.ts +13 -0
- package/dist/types/mutex/exceptions/MutexTimeoutException.d.ts +16 -0
- package/dist/types/mutex/lib/LoadDriver.d.ts +6 -0
- package/dist/types/mutex/lib/Names.d.ts +14 -0
- package/dist/types/mutex/options/FileMutexOptions.d.ts +33 -0
- package/dist/types/mutex/options/MemoryMutexOptions.d.ts +27 -0
- package/dist/types/mutex/options/MysqlMutexOptions.d.ts +70 -0
- package/dist/types/mutex/options/PostgresMutexOptions.d.ts +83 -0
- package/dist/types/mutex/options/RedisMutexOptions.d.ts +71 -0
- package/package.json +57 -4
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by the {@link Mutex} methods when the lock store fails (unreachable, a failed query, a file error), its
|
|
4
|
+
* message carrying the driver's error. An automatic renewal failing this way makes the lock lost instead. Its `errno` is
|
|
5
|
+
* `'E_MUTEX_DRIVER'`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MutexDriverException extends Exception {
|
|
8
|
+
/**
|
|
9
|
+
* `'E_MUTEX_DRIVER'`.
|
|
10
|
+
*/
|
|
11
|
+
errno: string | number;
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MutexDriverException = void 0;
|
|
4
|
+
const core_1 = require("@lakutata/core");
|
|
5
|
+
/**
|
|
6
|
+
* Thrown by the {@link Mutex} methods when the lock store fails (unreachable, a failed query, a file error), its
|
|
7
|
+
* message carrying the driver's error. An automatic renewal failing this way makes the lock lost instead. Its `errno` is
|
|
8
|
+
* `'E_MUTEX_DRIVER'`.
|
|
9
|
+
*/
|
|
10
|
+
class MutexDriverException extends core_1.Exception {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
/**
|
|
14
|
+
* `'E_MUTEX_DRIVER'`.
|
|
15
|
+
*/
|
|
16
|
+
this.errno = 'E_MUTEX_DRIVER';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.MutexDriverException = MutexDriverException;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by the first acquisition of a {@link Mutex} (or a driver) whose client package is not installed: `redis` for
|
|
4
|
+
* the Redis driver, `pg` for PostgreSQL, `mysql2` for MySQL. Its message names the package to install. Its `errno` is
|
|
5
|
+
* `'E_MUTEX_DRIVER_NOT_FOUND'`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MutexDriverNotFoundException extends Exception {
|
|
8
|
+
/**
|
|
9
|
+
* `'E_MUTEX_DRIVER_NOT_FOUND'`.
|
|
10
|
+
*/
|
|
11
|
+
errno: string | number;
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MutexDriverNotFoundException = void 0;
|
|
4
|
+
const core_1 = require("@lakutata/core");
|
|
5
|
+
/**
|
|
6
|
+
* Thrown by the first acquisition of a {@link Mutex} (or a driver) whose client package is not installed: `redis` for
|
|
7
|
+
* the Redis driver, `pg` for PostgreSQL, `mysql2` for MySQL. Its message names the package to install. Its `errno` is
|
|
8
|
+
* `'E_MUTEX_DRIVER_NOT_FOUND'`.
|
|
9
|
+
*/
|
|
10
|
+
class MutexDriverNotFoundException extends core_1.Exception {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
/**
|
|
14
|
+
* `'E_MUTEX_DRIVER_NOT_FOUND'`.
|
|
15
|
+
*/
|
|
16
|
+
this.errno = 'E_MUTEX_DRIVER_NOT_FOUND';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.MutexDriverNotFoundException = MutexDriverNotFoundException;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* The abort reason of {@link MutexLock.signal} when a lock is lost: a renewal found it expired or taken by another
|
|
4
|
+
* holder, a renewal failed, or the connection holding it closed. It is not thrown by the component: the work holding the
|
|
5
|
+
* lock meets it through the signal (`signal.throwIfAborted()`, an `AbortSignal`-aware API). Its `errno` is
|
|
6
|
+
* `'E_MUTEX_LOST'`.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MutexLostException extends Exception {
|
|
9
|
+
/**
|
|
10
|
+
* `'E_MUTEX_LOST'`.
|
|
11
|
+
*/
|
|
12
|
+
errno: string | number;
|
|
13
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MutexLostException = void 0;
|
|
4
|
+
const core_1 = require("@lakutata/core");
|
|
5
|
+
/**
|
|
6
|
+
* The abort reason of {@link MutexLock.signal} when a lock is lost: a renewal found it expired or taken by another
|
|
7
|
+
* holder, a renewal failed, or the connection holding it closed. It is not thrown by the component: the work holding the
|
|
8
|
+
* lock meets it through the signal (`signal.throwIfAborted()`, an `AbortSignal`-aware API). Its `errno` is
|
|
9
|
+
* `'E_MUTEX_LOST'`.
|
|
10
|
+
*/
|
|
11
|
+
class MutexLostException extends core_1.Exception {
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
/**
|
|
15
|
+
* `'E_MUTEX_LOST'`.
|
|
16
|
+
*/
|
|
17
|
+
this.errno = 'E_MUTEX_LOST';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.MutexLostException = MutexLostException;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Exception } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by {@link Mutex.acquire} and {@link Mutex.synchronized} when the lock is not acquired before the timeout
|
|
4
|
+
* (another holder kept it), and by a {@link Synchronized} action whose lock is held by another request (HTTP 409
|
|
5
|
+
* Conflict). Its `errno` is `'E_MUTEX_TIMEOUT'`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class MutexTimeoutException extends Exception {
|
|
8
|
+
/**
|
|
9
|
+
* `'E_MUTEX_TIMEOUT'`.
|
|
10
|
+
*/
|
|
11
|
+
errno: string | number;
|
|
12
|
+
/**
|
|
13
|
+
* The HTTP status the transports answer with: 409 (Conflict).
|
|
14
|
+
*/
|
|
15
|
+
statusCode: number;
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MutexTimeoutException = void 0;
|
|
4
|
+
const core_1 = require("@lakutata/core");
|
|
5
|
+
/**
|
|
6
|
+
* Thrown by {@link Mutex.acquire} and {@link Mutex.synchronized} when the lock is not acquired before the timeout
|
|
7
|
+
* (another holder kept it), and by a {@link Synchronized} action whose lock is held by another request (HTTP 409
|
|
8
|
+
* Conflict). Its `errno` is `'E_MUTEX_TIMEOUT'`.
|
|
9
|
+
*/
|
|
10
|
+
class MutexTimeoutException extends core_1.Exception {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
/**
|
|
14
|
+
* `'E_MUTEX_TIMEOUT'`.
|
|
15
|
+
*/
|
|
16
|
+
this.errno = 'E_MUTEX_TIMEOUT';
|
|
17
|
+
/**
|
|
18
|
+
* The HTTP status the transports answer with: 409 (Conflict).
|
|
19
|
+
*/
|
|
20
|
+
this.statusCode = 409;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.MutexTimeoutException = MutexTimeoutException;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load the client package of a driver (an optional dependency)
|
|
3
|
+
* @param member a member of its API, to find it in the ESM namespace or the CommonJS exports
|
|
4
|
+
* @param packageName
|
|
5
|
+
*/
|
|
6
|
+
export declare function loadDriver<T = any>(member: string, packageName: string): Promise<T>;
|
|
@@ -0,0 +1,64 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadDriver = loadDriver;
|
|
37
|
+
const MutexDriverNotFoundException_js_1 = require("../exceptions/MutexDriverNotFoundException.js");
|
|
38
|
+
/**
|
|
39
|
+
* Whether an error reports the package itself as missing
|
|
40
|
+
* @param error
|
|
41
|
+
* @param packageName
|
|
42
|
+
*/
|
|
43
|
+
function isPackageMissing(error, packageName) {
|
|
44
|
+
const { code, message } = error;
|
|
45
|
+
if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND')
|
|
46
|
+
return false;
|
|
47
|
+
return !!message && (message.includes(`'${packageName}'`) || message.includes(`"${packageName}"`));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Load the client package of a driver (an optional dependency)
|
|
51
|
+
* @param member a member of its API, to find it in the ESM namespace or the CommonJS exports
|
|
52
|
+
* @param packageName
|
|
53
|
+
*/
|
|
54
|
+
async function loadDriver(member, packageName) {
|
|
55
|
+
try {
|
|
56
|
+
const driver = await Promise.resolve(`${packageName}`).then(s => __importStar(require(s)));
|
|
57
|
+
return (driver[member] === undefined && driver.default ? driver.default : driver);
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
if (!isPackageMissing(e, packageName))
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
63
|
+
throw new MutexDriverNotFoundException_js_1.MutexDriverNotFoundException('Package "{packageName}" is required for this driver of the locks. Run "npm install {packageName}".', { packageName: packageName });
|
|
64
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The token of a lock acquired (its holder checked by it)
|
|
3
|
+
*/
|
|
4
|
+
export declare function lockToken(): string;
|
|
5
|
+
/**
|
|
6
|
+
* The digest of the name of a lock (hexadecimal)
|
|
7
|
+
* @param name
|
|
8
|
+
*/
|
|
9
|
+
export declare function nameDigest(name: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* The key of 64 bits of the name of a lock (the advisory locks of PostgreSQL), a signed bigint as a string
|
|
12
|
+
* @param name
|
|
13
|
+
*/
|
|
14
|
+
export declare function nameKey64(name: string): string;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lockToken = lockToken;
|
|
4
|
+
exports.nameDigest = nameDigest;
|
|
5
|
+
exports.nameKey64 = nameKey64;
|
|
6
|
+
const node_crypto_1 = require("node:crypto");
|
|
7
|
+
/**
|
|
8
|
+
* The token of a lock acquired (its holder checked by it)
|
|
9
|
+
*/
|
|
10
|
+
function lockToken() {
|
|
11
|
+
return (0, node_crypto_1.randomBytes)(16).toString('hex');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The digest of the name of a lock (hexadecimal)
|
|
15
|
+
* @param name
|
|
16
|
+
*/
|
|
17
|
+
function nameDigest(name) {
|
|
18
|
+
return (0, node_crypto_1.createHash)('sha256').update(name).digest('hex');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The key of 64 bits of the name of a lock (the advisory locks of PostgreSQL), a signed bigint as a string
|
|
22
|
+
* @param name
|
|
23
|
+
*/
|
|
24
|
+
function nameKey64(name) {
|
|
25
|
+
return (0, node_crypto_1.createHash)('sha256').update(name).digest().readBigInt64BE(0).toString();
|
|
26
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DTO } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* The options of the file driver ({@link FileMutexDriver}): one lock file per lock in a directory, shared by the
|
|
4
|
+
* processes of one host using the same directory (several workers or applications of a machine). It needs no package.
|
|
5
|
+
* The locks expire after their `ttl` unless renewed, a lock whose process is gone is taken over at once, and there is no
|
|
6
|
+
* fencing token.
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import {Application} from 'lakutata'
|
|
10
|
+
* import {Mutex} from 'lakutata/com/mutex'
|
|
11
|
+
*
|
|
12
|
+
* Application.run(() => ({
|
|
13
|
+
* id: 'file-mutex.app',
|
|
14
|
+
* name: 'FileMutex',
|
|
15
|
+
* components: {
|
|
16
|
+
* //Every worker of this machine uses the same directory
|
|
17
|
+
* mutex: {class: Mutex, driver: {type: 'file', directory: '/var/lock/my-app'}}
|
|
18
|
+
* }
|
|
19
|
+
* }))
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare class FileMutexOptions extends DTO {
|
|
23
|
+
/**
|
|
24
|
+
* The driver type: `'file'`.
|
|
25
|
+
*/
|
|
26
|
+
type: 'file';
|
|
27
|
+
/**
|
|
28
|
+
* The directory of the lock files, created when missing. The processes sharing the locks must use the same one; the
|
|
29
|
+
* default depends on the operating system's temporary directory, which can differ between users.
|
|
30
|
+
* @default path.join(os.tmpdir(), 'lakutata-mutex')
|
|
31
|
+
*/
|
|
32
|
+
directory?: string;
|
|
33
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.FileMutexOptions = void 0;
|
|
13
|
+
const core_1 = require("@lakutata/core");
|
|
14
|
+
const dto_1 = require("@lakutata/core/decorator/dto");
|
|
15
|
+
/**
|
|
16
|
+
* The options of the file driver ({@link FileMutexDriver}): one lock file per lock in a directory, shared by the
|
|
17
|
+
* processes of one host using the same directory (several workers or applications of a machine). It needs no package.
|
|
18
|
+
* The locks expire after their `ttl` unless renewed, a lock whose process is gone is taken over at once, and there is no
|
|
19
|
+
* fencing token.
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import {Application} from 'lakutata'
|
|
23
|
+
* import {Mutex} from 'lakutata/com/mutex'
|
|
24
|
+
*
|
|
25
|
+
* Application.run(() => ({
|
|
26
|
+
* id: 'file-mutex.app',
|
|
27
|
+
* name: 'FileMutex',
|
|
28
|
+
* components: {
|
|
29
|
+
* //Every worker of this machine uses the same directory
|
|
30
|
+
* mutex: {class: Mutex, driver: {type: 'file', directory: '/var/lock/my-app'}}
|
|
31
|
+
* }
|
|
32
|
+
* }))
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
class FileMutexOptions extends core_1.DTO {
|
|
36
|
+
}
|
|
37
|
+
exports.FileMutexOptions = FileMutexOptions;
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, dto_1.Expect)(core_1.DTO.String().valid('file').required()),
|
|
40
|
+
__metadata("design:type", String)
|
|
41
|
+
], FileMutexOptions.prototype, "type", void 0);
|
|
42
|
+
__decorate([
|
|
43
|
+
(0, dto_1.Expect)(core_1.DTO.String().optional()),
|
|
44
|
+
__metadata("design:type", String)
|
|
45
|
+
], FileMutexOptions.prototype, "directory", void 0);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { DTO } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* The options of the memory driver ({@link MemoryMutexDriver}), the default of a {@link Mutex}: the locks live in the
|
|
4
|
+
* process memory, shared by the components of the process and invisible to the other processes. For development, tests
|
|
5
|
+
* and an application running as a single process; it needs no package. The locks expire after their `ttl` unless
|
|
6
|
+
* renewed, and carry fencing tokens counted by the process.
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import {Application} from 'lakutata'
|
|
10
|
+
* import {Mutex} from 'lakutata/com/mutex'
|
|
11
|
+
*
|
|
12
|
+
* Application.run(() => ({
|
|
13
|
+
* id: 'memory-mutex.app',
|
|
14
|
+
* name: 'MemoryMutex',
|
|
15
|
+
* components: {
|
|
16
|
+
* //The same as {class: Mutex}
|
|
17
|
+
* mutex: {class: Mutex, driver: {type: 'memory'}}
|
|
18
|
+
* }
|
|
19
|
+
* }))
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare class MemoryMutexOptions extends DTO {
|
|
23
|
+
/**
|
|
24
|
+
* The driver type: `'memory'`.
|
|
25
|
+
*/
|
|
26
|
+
type: 'memory';
|
|
27
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MemoryMutexOptions = void 0;
|
|
13
|
+
const core_1 = require("@lakutata/core");
|
|
14
|
+
const dto_1 = require("@lakutata/core/decorator/dto");
|
|
15
|
+
/**
|
|
16
|
+
* The options of the memory driver ({@link MemoryMutexDriver}), the default of a {@link Mutex}: the locks live in the
|
|
17
|
+
* process memory, shared by the components of the process and invisible to the other processes. For development, tests
|
|
18
|
+
* and an application running as a single process; it needs no package. The locks expire after their `ttl` unless
|
|
19
|
+
* renewed, and carry fencing tokens counted by the process.
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import {Application} from 'lakutata'
|
|
23
|
+
* import {Mutex} from 'lakutata/com/mutex'
|
|
24
|
+
*
|
|
25
|
+
* Application.run(() => ({
|
|
26
|
+
* id: 'memory-mutex.app',
|
|
27
|
+
* name: 'MemoryMutex',
|
|
28
|
+
* components: {
|
|
29
|
+
* //The same as {class: Mutex}
|
|
30
|
+
* mutex: {class: Mutex, driver: {type: 'memory'}}
|
|
31
|
+
* }
|
|
32
|
+
* }))
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
class MemoryMutexOptions extends core_1.DTO {
|
|
36
|
+
}
|
|
37
|
+
exports.MemoryMutexOptions = MemoryMutexOptions;
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, dto_1.Expect)(core_1.DTO.String().valid('memory').required()),
|
|
40
|
+
__metadata("design:type", String)
|
|
41
|
+
], MemoryMutexOptions.prototype, "type", void 0);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { DTO } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* The options of the MySQL driver ({@link MysqlMutexDriver}), for MySQL or MariaDB: the locks are shared by every
|
|
4
|
+
* instance connected to the same server. It needs the optional peer dependency `mysql2` (`npm install mysql2`, 3):
|
|
5
|
+
* without it, the first acquisition fails with {@link MutexDriverNotFoundException}. The driver connects at the first
|
|
6
|
+
* acquisition, not when the component is created.
|
|
7
|
+
*
|
|
8
|
+
* In the `'advisory'` mode (the default), the locks are named locks (`GET_LOCK`) of one connection: they do not expire,
|
|
9
|
+
* MySQL releases them when the connection closes (a crashed process frees them at once), and they are all lost when it
|
|
10
|
+
* closes or fails. They have no fencing token, and are not replicated by the clusters (Galera, Group Replication): every
|
|
11
|
+
* holder must connect to the same server. In the `'table'` mode, the locks are rows of a table created at the first use:
|
|
12
|
+
* they expire after their `ttl` unless renewed, work through the poolers and the clusters, and carry fencing tokens.
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import {Application} from 'lakutata'
|
|
16
|
+
* import {Mutex} from 'lakutata/com/mutex'
|
|
17
|
+
*
|
|
18
|
+
* Application.run(() => ({
|
|
19
|
+
* id: 'mysql-mutex.app',
|
|
20
|
+
* name: 'MysqlMutex',
|
|
21
|
+
* components: {
|
|
22
|
+
* mutex: {
|
|
23
|
+
* class: Mutex,
|
|
24
|
+
* driver: {type: 'mysql', host: 'db', database: 'app', username: 'app', password: process.env.DB_PASSWORD ?? ''}
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* }))
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class MysqlMutexOptions extends DTO {
|
|
31
|
+
/**
|
|
32
|
+
* The driver type: `'mysql'`.
|
|
33
|
+
*/
|
|
34
|
+
type: 'mysql';
|
|
35
|
+
/**
|
|
36
|
+
* The host name or IP address of the server.
|
|
37
|
+
*/
|
|
38
|
+
host: string;
|
|
39
|
+
/**
|
|
40
|
+
* The port of the server.
|
|
41
|
+
* @default 3306
|
|
42
|
+
*/
|
|
43
|
+
port?: number;
|
|
44
|
+
/**
|
|
45
|
+
* The database holding the table of the `table` mode (the named locks are global to the server).
|
|
46
|
+
*/
|
|
47
|
+
database: string;
|
|
48
|
+
/**
|
|
49
|
+
* The user name.
|
|
50
|
+
*/
|
|
51
|
+
username: string;
|
|
52
|
+
/**
|
|
53
|
+
* The password (`''` for none).
|
|
54
|
+
*/
|
|
55
|
+
password: string;
|
|
56
|
+
/**
|
|
57
|
+
* How the locks are held: `'advisory'`, named locks of one connection, released when it closes (no expiration, no
|
|
58
|
+
* fencing token, not replicated by the clusters); `'table'`, rows of a table expiring unless renewed, with fencing
|
|
59
|
+
* tokens, through the poolers and the clusters.
|
|
60
|
+
* @default 'advisory'
|
|
61
|
+
*/
|
|
62
|
+
mode?: 'advisory' | 'table';
|
|
63
|
+
/**
|
|
64
|
+
* The table of the `table` mode, in the connection's database, created at the first use with its counter table
|
|
65
|
+
* `<table>_fence`; a name of letters, digits and `_`. An invalid name fails the validation of the options
|
|
66
|
+
* (`InvalidValueException`).
|
|
67
|
+
* @default 'lakutata_mutex'
|
|
68
|
+
*/
|
|
69
|
+
table?: string;
|
|
70
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MysqlMutexOptions = void 0;
|
|
13
|
+
const core_1 = require("@lakutata/core");
|
|
14
|
+
const dto_1 = require("@lakutata/core/decorator/dto");
|
|
15
|
+
/**
|
|
16
|
+
* The options of the MySQL driver ({@link MysqlMutexDriver}), for MySQL or MariaDB: the locks are shared by every
|
|
17
|
+
* instance connected to the same server. It needs the optional peer dependency `mysql2` (`npm install mysql2`, 3):
|
|
18
|
+
* without it, the first acquisition fails with {@link MutexDriverNotFoundException}. The driver connects at the first
|
|
19
|
+
* acquisition, not when the component is created.
|
|
20
|
+
*
|
|
21
|
+
* In the `'advisory'` mode (the default), the locks are named locks (`GET_LOCK`) of one connection: they do not expire,
|
|
22
|
+
* MySQL releases them when the connection closes (a crashed process frees them at once), and they are all lost when it
|
|
23
|
+
* closes or fails. They have no fencing token, and are not replicated by the clusters (Galera, Group Replication): every
|
|
24
|
+
* holder must connect to the same server. In the `'table'` mode, the locks are rows of a table created at the first use:
|
|
25
|
+
* they expire after their `ttl` unless renewed, work through the poolers and the clusters, and carry fencing tokens.
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import {Application} from 'lakutata'
|
|
29
|
+
* import {Mutex} from 'lakutata/com/mutex'
|
|
30
|
+
*
|
|
31
|
+
* Application.run(() => ({
|
|
32
|
+
* id: 'mysql-mutex.app',
|
|
33
|
+
* name: 'MysqlMutex',
|
|
34
|
+
* components: {
|
|
35
|
+
* mutex: {
|
|
36
|
+
* class: Mutex,
|
|
37
|
+
* driver: {type: 'mysql', host: 'db', database: 'app', username: 'app', password: process.env.DB_PASSWORD ?? ''}
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* }))
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
class MysqlMutexOptions extends core_1.DTO {
|
|
44
|
+
}
|
|
45
|
+
exports.MysqlMutexOptions = MysqlMutexOptions;
|
|
46
|
+
__decorate([
|
|
47
|
+
(0, dto_1.Expect)(core_1.DTO.String().valid('mysql').required()),
|
|
48
|
+
__metadata("design:type", String)
|
|
49
|
+
], MysqlMutexOptions.prototype, "type", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, dto_1.Expect)(core_1.DTO.String().required()),
|
|
52
|
+
__metadata("design:type", String)
|
|
53
|
+
], MysqlMutexOptions.prototype, "host", void 0);
|
|
54
|
+
__decorate([
|
|
55
|
+
(0, dto_1.Expect)(core_1.DTO.Number().port().optional().default(3306)),
|
|
56
|
+
__metadata("design:type", Number)
|
|
57
|
+
], MysqlMutexOptions.prototype, "port", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
(0, dto_1.Expect)(core_1.DTO.String().required()),
|
|
60
|
+
__metadata("design:type", String)
|
|
61
|
+
], MysqlMutexOptions.prototype, "database", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
(0, dto_1.Expect)(core_1.DTO.String().required()),
|
|
64
|
+
__metadata("design:type", String)
|
|
65
|
+
], MysqlMutexOptions.prototype, "username", void 0);
|
|
66
|
+
__decorate([
|
|
67
|
+
(0, dto_1.Expect)(core_1.DTO.String().allow('').required()),
|
|
68
|
+
__metadata("design:type", String)
|
|
69
|
+
], MysqlMutexOptions.prototype, "password", void 0);
|
|
70
|
+
__decorate([
|
|
71
|
+
(0, dto_1.Expect)(core_1.DTO.String().valid('advisory', 'table').optional().default('advisory')),
|
|
72
|
+
__metadata("design:type", String)
|
|
73
|
+
], MysqlMutexOptions.prototype, "mode", void 0);
|
|
74
|
+
__decorate([
|
|
75
|
+
(0, dto_1.Expect)(core_1.DTO.String().pattern(/^[a-zA-Z_][a-zA-Z0-9_]*$/).optional().default('lakutata_mutex')),
|
|
76
|
+
__metadata("design:type", String)
|
|
77
|
+
], MysqlMutexOptions.prototype, "table", void 0);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { DTO } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* The options of the PostgreSQL driver ({@link PostgresMutexDriver}): the locks are shared by every instance connected
|
|
4
|
+
* to the same database. It needs the optional peer dependency `pg` (`npm install pg`, 8): without it, the first
|
|
5
|
+
* acquisition fails with {@link MutexDriverNotFoundException}. The driver connects at the first acquisition, not when
|
|
6
|
+
* the component is created.
|
|
7
|
+
*
|
|
8
|
+
* In the `'advisory'` mode (the default), the locks are session advisory locks of one connection: they do not expire,
|
|
9
|
+
* PostgreSQL releases them when the connection closes (a crashed process frees them at once), and they are all lost
|
|
10
|
+
* when it closes or fails. They have no fencing token, and do not work through a pooler in transaction mode
|
|
11
|
+
* (PgBouncer). In the `'table'` mode, the locks are rows of a table created at the first use: they expire after their
|
|
12
|
+
* `ttl` unless renewed, work through the poolers, and carry fencing tokens.
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import {Application} from 'lakutata'
|
|
16
|
+
* import {Mutex} from 'lakutata/com/mutex'
|
|
17
|
+
*
|
|
18
|
+
* Application.run(() => ({
|
|
19
|
+
* id: 'postgres-mutex.app',
|
|
20
|
+
* name: 'PostgresMutex',
|
|
21
|
+
* components: {
|
|
22
|
+
* mutex: {
|
|
23
|
+
* class: Mutex,
|
|
24
|
+
* driver: {
|
|
25
|
+
* type: 'postgres',
|
|
26
|
+
* host: 'db',
|
|
27
|
+
* database: 'app',
|
|
28
|
+
* username: 'app',
|
|
29
|
+
* password: process.env.DB_PASSWORD ?? '',
|
|
30
|
+
* //Through PgBouncer: rows of a table, with fencing tokens
|
|
31
|
+
* mode: 'table'
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
* }
|
|
35
|
+
* }))
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare class PostgresMutexOptions extends DTO {
|
|
39
|
+
/**
|
|
40
|
+
* The driver type: `'postgres'`.
|
|
41
|
+
*/
|
|
42
|
+
type: 'postgres';
|
|
43
|
+
/**
|
|
44
|
+
* The host name or IP address of the server.
|
|
45
|
+
*/
|
|
46
|
+
host: string;
|
|
47
|
+
/**
|
|
48
|
+
* The port of the server.
|
|
49
|
+
* @default 5432
|
|
50
|
+
*/
|
|
51
|
+
port?: number;
|
|
52
|
+
/**
|
|
53
|
+
* The database holding the locks (and the table of the `table` mode).
|
|
54
|
+
*/
|
|
55
|
+
database: string;
|
|
56
|
+
/**
|
|
57
|
+
* The user name.
|
|
58
|
+
*/
|
|
59
|
+
username: string;
|
|
60
|
+
/**
|
|
61
|
+
* The password (`''` for none).
|
|
62
|
+
*/
|
|
63
|
+
password: string;
|
|
64
|
+
/**
|
|
65
|
+
* Whether to connect with TLS (`ssl: true` given to `pg`, which verifies the server certificate).
|
|
66
|
+
* @default false
|
|
67
|
+
*/
|
|
68
|
+
ssl?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* How the locks are held: `'advisory'`, session advisory locks of one connection, released when it closes (no
|
|
71
|
+
* expiration, no fencing token, not through a transaction pooler); `'table'`, rows of a table expiring unless renewed,
|
|
72
|
+
* with fencing tokens, through the poolers.
|
|
73
|
+
* @default 'advisory'
|
|
74
|
+
*/
|
|
75
|
+
mode?: 'advisory' | 'table';
|
|
76
|
+
/**
|
|
77
|
+
* The table of the `table` mode, created at the first use with its sequence `<table>_fence`; a name of letters,
|
|
78
|
+
* digits and `_`, optionally qualified by its schema (`locks.mutex`). An invalid name fails the validation of the options
|
|
79
|
+
* (`InvalidValueException`).
|
|
80
|
+
* @default 'lakutata_mutex'
|
|
81
|
+
*/
|
|
82
|
+
table?: string;
|
|
83
|
+
}
|