better-lock 3.1.0 → 3.3.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/README.md +35 -1
- package/dist/better_lock.d.ts +13 -7
- package/dist/better_lock.js +60 -5
- package/dist/better_lock.js.map +1 -1
- package/dist/errors.d.ts +1 -0
- package/dist/errors.js +7 -1
- package/dist/errors.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/docs/assets/search.js +1 -1
- package/docs/classes/BetterLockError.html +3 -3
- package/docs/classes/BetterLockExecutionTimeoutError.html +6 -6
- package/docs/classes/BetterLockInternalError.html +3 -3
- package/docs/classes/BetterLockInvalidArgumentError.html +4 -4
- package/docs/classes/BetterLockJobAbortedError.html +5 -5
- package/docs/classes/BetterLockQueueOverflowError.html +8 -8
- package/docs/classes/BetterLockWaitTimeoutError.html +6 -6
- package/docs/classes/_internal_.BetterLock.html +189 -7
- package/docs/classes/_internal_.KeyQueue.html +4 -4
- package/docs/classes/_internal_.LockJob.html +13 -13
- package/docs/functions/_internal_.__home_panta_dev_pantas_better_lock_src_errors_.isAcquisitionFailureError.html +62 -0
- package/docs/index.html +13 -2
- package/docs/interfaces/BetterLockJobOptions.html +27 -4
- package/docs/interfaces/BetterLockOptions.html +26 -8
- package/docs/modules/_internal_.__home_panta_dev_pantas_better_lock_src_errors_.html +6 -1
- package/docs/types/BetterLockErrorName.html +1 -1
- package/docs/types/BetterLockExecutor.html +1 -1
- package/docs/types/BetterLockKey.html +1 -1
- package/docs/types/BetterLockQueueEjectionStrategy.html +1 -1
- package/docs/types/_internal_.ICallback.html +1 -1
- package/docs/types/_internal_.ICallbackExecutor.html +1 -1
- package/docs/types/_internal_.IErrorExports.html +1 -1
- package/docs/types/_internal_.IPromiseExecutor.html +1 -1
- package/docs/variables/BetterLock.html +1 -1
- package/package.json +3 -4
- package/spec/better_lock.spec.ts +112 -0
- package/src/better_lock.ts +97 -13
- package/src/errors.ts +14 -1
- package/src/types.ts +5 -0
- package/tsconfig.build.json +6 -0
- package/tsconfig.json +1 -0
package/src/better_lock.ts
CHANGED
|
@@ -5,11 +5,12 @@ import {
|
|
|
5
5
|
BetterLockJobAbortedError,
|
|
6
6
|
BetterLockQueueOverflowError,
|
|
7
7
|
BetterLockWaitTimeoutError,
|
|
8
|
+
isAcquisitionFailureError,
|
|
8
9
|
} from './errors';
|
|
9
10
|
import { KeyQueue, LockJob } from './internals';
|
|
10
11
|
import { ILockJobOptions, IOptions } from './options';
|
|
11
12
|
import * as tools from './tools';
|
|
12
|
-
import { ICallback, ICallbackExecutor, ILockKey, IPromiseExecutor } from './types';
|
|
13
|
+
import { ICallback, ICallbackExecutor, ILockKey, IPromiseExecutor, IValidResult } from './types';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Main better lock class.
|
|
@@ -80,30 +81,30 @@ export class BetterLock {
|
|
|
80
81
|
);
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
public acquire<TResult>(
|
|
84
|
+
public acquire<TResult extends IValidResult>(
|
|
84
85
|
executor: IPromiseExecutor<TResult>,
|
|
85
86
|
jobOptions?: ILockJobOptions
|
|
86
87
|
): Promise<TResult>;
|
|
87
|
-
public acquire<TResult>(
|
|
88
|
+
public acquire<TResult extends IValidResult>(
|
|
88
89
|
executor: ICallbackExecutor<TResult>,
|
|
89
90
|
jobOptions?: ILockJobOptions
|
|
90
91
|
): Promise<TResult>;
|
|
91
|
-
public acquire<TResult>(
|
|
92
|
+
public acquire<TResult extends IValidResult>(
|
|
92
93
|
executor: ICallbackExecutor<TResult>,
|
|
93
94
|
callback: ICallback<TResult>,
|
|
94
95
|
jobOptions?: ILockJobOptions
|
|
95
96
|
): void;
|
|
96
|
-
public acquire<TResult>(
|
|
97
|
+
public acquire<TResult extends IValidResult>(
|
|
97
98
|
key: ILockKey | Array<ILockKey>,
|
|
98
99
|
executor: IPromiseExecutor<TResult>,
|
|
99
100
|
jobOptions?: ILockJobOptions
|
|
100
101
|
): Promise<TResult>;
|
|
101
|
-
public acquire<TResult>(
|
|
102
|
+
public acquire<TResult extends IValidResult>(
|
|
102
103
|
key: ILockKey | Array<ILockKey>,
|
|
103
104
|
executor: ICallbackExecutor<TResult>,
|
|
104
105
|
jobOptions?: ILockJobOptions
|
|
105
106
|
): Promise<TResult>;
|
|
106
|
-
public acquire<TResult>(
|
|
107
|
+
public acquire<TResult extends IValidResult>(
|
|
107
108
|
key: ILockKey | Array<ILockKey>,
|
|
108
109
|
executor: ICallbackExecutor<TResult>,
|
|
109
110
|
callback: ICallback<TResult>,
|
|
@@ -125,7 +126,7 @@ export class BetterLock {
|
|
|
125
126
|
* @param jobOptions Options to be applied on this job only
|
|
126
127
|
*/
|
|
127
128
|
public acquire(key, executor?, callback?, jobOptions?) {
|
|
128
|
-
if (tools.isFunction(key)
|
|
129
|
+
if (tools.isFunction(key)) {
|
|
129
130
|
// Presume we weren't given a key (first form)
|
|
130
131
|
jobOptions = callback;
|
|
131
132
|
callback = executor;
|
|
@@ -189,9 +190,12 @@ export class BetterLock {
|
|
|
189
190
|
const job = new LockJob(keys, executor, callback, effectiveJobOptions);
|
|
190
191
|
|
|
191
192
|
// Set incoming stack
|
|
192
|
-
if (
|
|
193
|
+
if (
|
|
194
|
+
effectiveJobOptions.extend_stack_traces &&
|
|
195
|
+
typeof (Error as any).captureStackTrace === 'function'
|
|
196
|
+
) {
|
|
193
197
|
const tempErr = new Error();
|
|
194
|
-
Error.captureStackTrace(tempErr, this.acquire);
|
|
198
|
+
(Error as any).captureStackTrace(tempErr, this.acquire);
|
|
195
199
|
job.incoming_stack = tempErr.stack;
|
|
196
200
|
}
|
|
197
201
|
|
|
@@ -224,6 +228,86 @@ export class BetterLock {
|
|
|
224
228
|
return (callback as any).promise;
|
|
225
229
|
}
|
|
226
230
|
|
|
231
|
+
public acquireOr<TResult extends IValidResult>(
|
|
232
|
+
failureResult: TResult,
|
|
233
|
+
executor: IPromiseExecutor<TResult>,
|
|
234
|
+
jobOptions?: ILockJobOptions
|
|
235
|
+
): Promise<TResult>;
|
|
236
|
+
public acquireOr<TResult extends IValidResult>(
|
|
237
|
+
failureResult: TResult,
|
|
238
|
+
executor: ICallbackExecutor<TResult>,
|
|
239
|
+
jobOptions?: ILockJobOptions
|
|
240
|
+
): Promise<TResult>;
|
|
241
|
+
public acquireOr<TResult extends IValidResult>(
|
|
242
|
+
failureResult: TResult,
|
|
243
|
+
executor: ICallbackExecutor<TResult>,
|
|
244
|
+
callback: ICallback<TResult>,
|
|
245
|
+
jobOptions?: ILockJobOptions
|
|
246
|
+
): void;
|
|
247
|
+
public acquireOr<TResult extends IValidResult>(
|
|
248
|
+
key: ILockKey | Array<ILockKey>,
|
|
249
|
+
failureResult: TResult,
|
|
250
|
+
executor: IPromiseExecutor<TResult>,
|
|
251
|
+
jobOptions?: ILockJobOptions
|
|
252
|
+
): Promise<TResult>;
|
|
253
|
+
public acquireOr<TResult extends IValidResult>(
|
|
254
|
+
key: ILockKey | Array<ILockKey>,
|
|
255
|
+
failureResult: TResult,
|
|
256
|
+
executor: ICallbackExecutor<TResult>,
|
|
257
|
+
jobOptions?: ILockJobOptions
|
|
258
|
+
): Promise<TResult>;
|
|
259
|
+
public acquireOr<TResult extends IValidResult>(
|
|
260
|
+
key: ILockKey | Array<ILockKey>,
|
|
261
|
+
failureResult: TResult,
|
|
262
|
+
executor: ICallbackExecutor<TResult>,
|
|
263
|
+
callback: ICallback<TResult>,
|
|
264
|
+
jobOptions?: ILockJobOptions
|
|
265
|
+
): void;
|
|
266
|
+
/**
|
|
267
|
+
* The same as acquire, except if the lock can't be acquired (the executor never gets called), instead of throwing
|
|
268
|
+
* an error, the lock will resolve/callback with the provided failureResult value (for example, a `null`).
|
|
269
|
+
* @param key Named key or array of keys for this particular call. Calls with different keys will be run in parallel. Not required.
|
|
270
|
+
* @param failureResult The value to return if the executor never get called. This happens instead of rejecting.
|
|
271
|
+
* @param executor Function that will run inside the lock. Required.
|
|
272
|
+
* @param callback Function to be called after the executor finishes, or there is an execution timeout. Leave out to use promises.
|
|
273
|
+
* @param jobOptions Options to be applied on this job only
|
|
274
|
+
*/
|
|
275
|
+
public acquireOr(key, failureResult, executor?, callback?, jobOptions?) {
|
|
276
|
+
if (tools.isFunction(failureResult)) {
|
|
277
|
+
// There is no key given. Reshuffle.
|
|
278
|
+
jobOptions = callback;
|
|
279
|
+
callback = executor;
|
|
280
|
+
executor = failureResult;
|
|
281
|
+
failureResult = key;
|
|
282
|
+
key = null;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (tools.isFunction(callback)) {
|
|
286
|
+
const originalCallback = callback;
|
|
287
|
+
callback = (err, ...results) => {
|
|
288
|
+
if (isAcquisitionFailureError(err)) {
|
|
289
|
+
originalCallback(null, failureResult);
|
|
290
|
+
} else {
|
|
291
|
+
originalCallback(err, ...results);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// noinspection JSVoidFunctionReturnValueUsed
|
|
297
|
+
let promiseResult = this.acquire(key, executor, callback, jobOptions) as any;
|
|
298
|
+
|
|
299
|
+
if (typeof promiseResult !== 'undefined') {
|
|
300
|
+
promiseResult = promiseResult.catch(err => {
|
|
301
|
+
if (isAcquisitionFailureError(err)) {
|
|
302
|
+
return failureResult;
|
|
303
|
+
}
|
|
304
|
+
throw err;
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return promiseResult;
|
|
309
|
+
}
|
|
310
|
+
|
|
227
311
|
/**
|
|
228
312
|
* Update state of given list of queues.
|
|
229
313
|
*/
|
|
@@ -275,7 +359,7 @@ export class BetterLock {
|
|
|
275
359
|
// We want to do the rest of this in a separate context, because we don't want user executor code
|
|
276
360
|
// to ever interfere with the code calling acquire().
|
|
277
361
|
|
|
278
|
-
|
|
362
|
+
setTimeout(() => {
|
|
279
363
|
// Make sure job hasn't been ended in the meantime
|
|
280
364
|
if (job.executed_at || job.ended_at) {
|
|
281
365
|
return;
|
|
@@ -336,7 +420,7 @@ export class BetterLock {
|
|
|
336
420
|
// "promise" is just some random value. We don't have to wait
|
|
337
421
|
lockDone(null, executorResult);
|
|
338
422
|
}
|
|
339
|
-
});
|
|
423
|
+
}, 0);
|
|
340
424
|
}
|
|
341
425
|
|
|
342
426
|
private onWaitTimeout(job: LockJob<any>) {
|
|
@@ -403,7 +487,7 @@ export class BetterLock {
|
|
|
403
487
|
job.callback.apply(null, callbackArgs);
|
|
404
488
|
} finally {
|
|
405
489
|
// Whatever happens, schedule a queue update
|
|
406
|
-
|
|
490
|
+
setTimeout(() => this.update(queuesToUpdate), 0);
|
|
407
491
|
}
|
|
408
492
|
}
|
|
409
493
|
|
package/src/errors.ts
CHANGED
|
@@ -51,7 +51,12 @@ export class BetterLockInternalError extends BetterLockError {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export class BetterLockInvalidArgumentError extends BetterLockError {
|
|
54
|
-
constructor(
|
|
54
|
+
constructor(
|
|
55
|
+
lockName,
|
|
56
|
+
public argument,
|
|
57
|
+
expected,
|
|
58
|
+
actual
|
|
59
|
+
) {
|
|
55
60
|
super(lockName, `Argument "${argument}" must be ${expected} (got: "${actual}")`);
|
|
56
61
|
this.argument = argument;
|
|
57
62
|
}
|
|
@@ -125,3 +130,11 @@ export class BetterLockJobAbortedError extends BetterLockError {
|
|
|
125
130
|
this.keys = job.keys;
|
|
126
131
|
}
|
|
127
132
|
}
|
|
133
|
+
|
|
134
|
+
export function isAcquisitionFailureError(err) {
|
|
135
|
+
return (
|
|
136
|
+
(err && err instanceof BetterLockQueueOverflowError) ||
|
|
137
|
+
err instanceof BetterLockWaitTimeoutError ||
|
|
138
|
+
err instanceof BetterLockJobAbortedError
|
|
139
|
+
);
|
|
140
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -27,3 +27,8 @@ export type IExecutor<TResult> = ICallbackExecutor<TResult> | IPromiseExecutor<T
|
|
|
27
27
|
* Key types that can be used for a lock.
|
|
28
28
|
*/
|
|
29
29
|
export type ILockKey = string | number | null | undefined;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Valid results are anything except functions
|
|
33
|
+
*/
|
|
34
|
+
export type IValidResult = Exclude<any, (...args: any[]) => any>;
|