better-lock 1.0.2 → 2.0.2-beta

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.
Files changed (55) hide show
  1. package/.eslintrc.js +24 -0
  2. package/.idea/better-lock.iml +1 -7
  3. package/.idea/codeStyles/Project.xml +336 -5
  4. package/.idea/compiler.xml +7 -0
  5. package/.idea/inspectionProfiles/Project_Default.xml +6 -2
  6. package/.idea/jsLibraryMappings.xml +0 -1
  7. package/.idea/markdown.xml +9 -0
  8. package/.idea/modules.xml +1 -1
  9. package/.idea/prettier.xml +8 -0
  10. package/.prettierrc.yaml +1 -3
  11. package/.travis.yml +2 -2
  12. package/README.md +113 -73
  13. package/dist/better_lock.d.ts +50 -0
  14. package/dist/better_lock.js +317 -0
  15. package/dist/better_lock.js.map +1 -0
  16. package/dist/errors.d.ts +44 -0
  17. package/dist/errors.js +131 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/index.d.ts +16 -0
  20. package/dist/index.js +28 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/internals.d.ts +75 -0
  23. package/dist/internals.js +75 -0
  24. package/dist/internals.js.map +1 -0
  25. package/dist/options.d.ts +54 -0
  26. package/dist/options.js +3 -0
  27. package/dist/options.js.map +1 -0
  28. package/dist/tools.d.ts +19 -0
  29. package/dist/tools.js +109 -0
  30. package/dist/tools.js.map +1 -0
  31. package/dist/types.d.ts +23 -0
  32. package/dist/types.js +3 -0
  33. package/dist/types.js.map +1 -0
  34. package/jest.config.js +4 -0
  35. package/package.json +32 -9
  36. package/spec/better_lock.spec.ts +614 -0
  37. package/src/better_lock.ts +430 -0
  38. package/src/errors.ts +124 -0
  39. package/src/index.ts +54 -0
  40. package/src/internals.ts +118 -0
  41. package/src/options.ts +63 -0
  42. package/src/tools.ts +111 -0
  43. package/src/types.ts +29 -0
  44. package/tsconfig.json +13 -0
  45. package/.idea/markdown-navigator/profiles_settings.xml +0 -3
  46. package/.idea/markdown-navigator.xml +0 -78
  47. package/.idea/misc.xml +0 -6
  48. package/.idea/watcherTasks.xml +0 -8
  49. package/index.js +0 -19
  50. package/spec/better_lock.spec.js +0 -602
  51. package/src/better_lock.js +0 -405
  52. package/src/errors.js +0 -81
  53. package/src/options.js +0 -104
  54. package/src/tools.js +0 -125
  55. package/src/types.js +0 -110
@@ -0,0 +1,430 @@
1
+ import {
2
+ BetterLockExecutionTimeoutError,
3
+ BetterLockInternalError,
4
+ BetterLockInvalidArgumentError,
5
+ BetterLockJobAbortedError,
6
+ BetterLockQueueOverflowError,
7
+ BetterLockWaitTimeoutError,
8
+ } from './errors';
9
+ import { KeyQueue, LockJob } from './internals';
10
+ import { ILockJobOptions, IOptions } from './options';
11
+ import * as tools from './tools';
12
+ import { ICallback, ICallbackExecutor, ILockKey, IPromiseExecutor } from './types';
13
+
14
+ /**
15
+ * Create a better lock object.
16
+ */
17
+ export class BetterLock {
18
+ /**
19
+ * Default options to be used when creating BetterLock instances.
20
+ */
21
+ static DEFAULT_OPTIONS: IOptions = {
22
+ extend_stack_traces: true,
23
+ promise_tester: p => p && typeof p.then === 'function',
24
+ };
25
+
26
+ private options: IOptions;
27
+ private log: (msg: string) => void;
28
+ private queues: { [key: string]: KeyQueue };
29
+
30
+ constructor(options?: IOptions) {
31
+ this.options = tools.assign({}, [BetterLock.DEFAULT_OPTIONS, options]);
32
+ this.log = tools.makeLog(this.options.name, this.options.log);
33
+ this.queues = {};
34
+ }
35
+
36
+ /**
37
+ * Return or create a key queue for given key
38
+ */
39
+ private getQueue(key: ILockKey): KeyQueue {
40
+ if (key === undefined || key === null) {
41
+ key = KeyQueue.DEFAULT_QUEUE_KEY;
42
+ }
43
+ let queue = this.queues[key];
44
+ if (!queue) {
45
+ queue = this.queues[key] = new KeyQueue(String(key));
46
+ }
47
+ return queue;
48
+ }
49
+
50
+ /**
51
+ * Returns true if the caller can *immediately* acquire the lock. There is nothing holding the key and nothing in the queue.
52
+ */
53
+ public canAcquire(key?: string): boolean {
54
+ const queue = this.getQueue(key);
55
+ return !queue.active && !queue.jobs.length;
56
+ }
57
+
58
+ private normalizeAndValidateKey(key: ILockKey) {
59
+ if (key === undefined) {
60
+ return null;
61
+ }
62
+ if (key === null) {
63
+ return null;
64
+ }
65
+ if (tools.isString(key)) {
66
+ return key;
67
+ }
68
+ if (tools.isNumber(key)) {
69
+ return String(key);
70
+ }
71
+ // Invalid key value
72
+ throw new BetterLockInvalidArgumentError(
73
+ this.options.name,
74
+ 'key',
75
+ 'an instance of ILockKey: string, number, undefined or null',
76
+ key
77
+ );
78
+ }
79
+
80
+ public acquire<TResult>(
81
+ executor: IPromiseExecutor<TResult>,
82
+ jobOptions?: ILockJobOptions
83
+ ): Promise<TResult>;
84
+ public acquire<TResult>(
85
+ executor: ICallbackExecutor<TResult>,
86
+ jobOptions?: ILockJobOptions
87
+ ): Promise<TResult>;
88
+ public acquire<TResult>(
89
+ executor: ICallbackExecutor<TResult>,
90
+ callback: ICallback<TResult>,
91
+ jobOptions?: ILockJobOptions
92
+ ): void;
93
+ public acquire<TResult>(
94
+ key: ILockKey | Array<ILockKey>,
95
+ executor: IPromiseExecutor<TResult>,
96
+ jobOptions?: ILockJobOptions
97
+ ): Promise<TResult>;
98
+ public acquire<TResult>(
99
+ key: ILockKey | Array<ILockKey>,
100
+ executor: ICallbackExecutor<TResult>,
101
+ jobOptions?: ILockJobOptions
102
+ ): Promise<TResult>;
103
+ public acquire<TResult>(
104
+ key: ILockKey | Array<ILockKey>,
105
+ executor: ICallbackExecutor<TResult>,
106
+ callback: ICallback<TResult>,
107
+ jobOptions?: ILockJobOptions
108
+ ): void;
109
+ /**
110
+ * Acquire the lock for given key or list of keys. If waiting on a list, keys will be acquired in order,
111
+ * as they become free. Any deadlock prevention must be handled by the caller.
112
+ *
113
+ * Once the lock is acquired, we will call the executor function, with a "done" method.
114
+ * You must call "done" to release the lock. Alternatively, return a Promise; lock will be released
115
+ * once promise resolves or rejects.
116
+ *
117
+ * Return values from your executor will be passed to callback (or the resulting promise).
118
+ *
119
+ * @param key Named key or array of keys for this particular call. Calls with different keys will be run in parallel. Not required.
120
+ * @param executor Function that will run inside the lock. Required.
121
+ * @param callback Function to be called after the executor finishes or if we never enter the lock (timeout, queue depletion). Leave out to use promises.
122
+ * @param jobOptions Options to be applied on this job only
123
+ */
124
+ public acquire(key, executor?, callback?, jobOptions?) {
125
+ if (tools.isFunction(key) || tools.isObject(key)) {
126
+ // Presume we weren't given a key (first form)
127
+ jobOptions = callback;
128
+ callback = executor;
129
+ executor = key;
130
+ key = null;
131
+ }
132
+
133
+ // Repackage "key" into an array of keys
134
+ const keys = [];
135
+ if (Array.isArray(key)) {
136
+ const arrayOfKeys = key;
137
+ // Make sure we don't add duplicates
138
+ const seenKeys = new Set();
139
+ for (let i = 0; i < arrayOfKeys.length; i++) {
140
+ const normalizedKey = this.normalizeAndValidateKey(arrayOfKeys[i]);
141
+ if (!seenKeys.has(normalizedKey)) {
142
+ keys.push(normalizedKey);
143
+ seenKeys.add(normalizedKey);
144
+ }
145
+ }
146
+ } else {
147
+ keys.push(this.normalizeAndValidateKey(key));
148
+ }
149
+
150
+ // Create callback wrapper for promise interface
151
+ if (!tools.isFunction(callback)) {
152
+ if (jobOptions === undefined) {
153
+ jobOptions = callback;
154
+ }
155
+
156
+ callback = tools.callbackWithPromise();
157
+ }
158
+
159
+ // Validate other options
160
+ if (!tools.isFunction(executor)) {
161
+ throw new BetterLockInvalidArgumentError(
162
+ this.options.name,
163
+ 'executor',
164
+ 'a function',
165
+ executor
166
+ );
167
+ }
168
+ if (!tools.isFunction(callback)) {
169
+ throw new BetterLockInvalidArgumentError(
170
+ this.options.name,
171
+ 'callback',
172
+ 'a function',
173
+ callback
174
+ );
175
+ }
176
+
177
+ // Prepare job options
178
+ const effectiveJobOptions = jobOptions
179
+ ? tools.assign({}, [this.options, jobOptions])
180
+ : // No need to create new object since these will be read-only and are subset of global options
181
+ this.options;
182
+
183
+ const job = new LockJob(keys, executor, callback, effectiveJobOptions);
184
+
185
+ // Set incoming stack
186
+ if (effectiveJobOptions.extend_stack_traces) {
187
+ const tempErr = new Error();
188
+ Error.captureStackTrace(tempErr, this.acquire);
189
+ job.incoming_stack = tempErr.stack;
190
+ }
191
+
192
+ // Add job to its key queues
193
+ const queuesToUpdate = [];
194
+ for (let i = 0; i < keys.length; i++) {
195
+ const queue = this.getQueue(keys[i]);
196
+ queue.jobs.push(job);
197
+ queuesToUpdate.push(queue);
198
+ }
199
+
200
+ // Start wait timer, if enabled
201
+ if (tools.isNumber(job.options.wait_timeout)) {
202
+ job.wait_timeout_id = setTimeout(() => this.onWaitTimeout(job), job.options.wait_timeout);
203
+
204
+ // NOTE: timeout of 0 will NOT trigger error if lock can be acquired immediately.
205
+ }
206
+
207
+ this.log(`Enqueued ${job}`);
208
+
209
+ // Perform update of queues this job has modified. We don't do this in next tick or something,
210
+ // because we want canAcquire to immediately return false
211
+ if (queuesToUpdate.length) {
212
+ this.update(queuesToUpdate);
213
+ } else {
214
+ // Special case. We are given empty list of keys. We will immediately execute jobs like this.
215
+ this.executeJob(job);
216
+ }
217
+
218
+ return (callback as any).promise;
219
+ }
220
+
221
+ /**
222
+ * Update state of given list of queues.
223
+ */
224
+ private update(queues: KeyQueue[]) {
225
+ for (let i = 0; i < queues.length; i++) {
226
+ const queue = queues[i];
227
+
228
+ // If key is available, have next job grab it
229
+ if (!queue.active && queue.jobs.length) {
230
+ const job = queue.jobs.splice(0, 1)[0];
231
+ queue.active = job;
232
+ job.waiting_count--;
233
+
234
+ if (job.waiting_count <= 0) {
235
+ // This job can be executed now.
236
+ this.executeJob(job);
237
+ }
238
+ }
239
+
240
+ // Handle wait queue overflow
241
+ if (tools.isNumber(this.options.queue_size) && this.options.queue_size < queue.jobs.length) {
242
+ // Overflow. Reject the most recent job
243
+ const mostRecentJob = queue.jobs[queue.jobs.length - 1];
244
+ this.log(
245
+ `${queue.toString()} has overflown, so most recent job (${mostRecentJob}) was kicked out`
246
+ );
247
+
248
+ this.endJob(mostRecentJob, [
249
+ new BetterLockQueueOverflowError(
250
+ this.options.name,
251
+ queue.key,
252
+ queue.jobs.length,
253
+ mostRecentJob
254
+ ),
255
+ ]);
256
+ }
257
+ }
258
+ }
259
+
260
+ private executeJob(job: LockJob<any>) {
261
+ this.log(`Executing ${job}`);
262
+
263
+ // Clear wait timeout
264
+ clearTimeout(job.wait_timeout_id);
265
+ job.wait_timeout_id = null;
266
+
267
+ // We want to do the rest of this in a separate context, because we don't want user executor code
268
+ // to ever interfere with the code calling acquire().
269
+
270
+ setImmediate(() => {
271
+ // Make sure job hasn't been ended in the meantime
272
+ if (job.executed_at || job.ended_at) {
273
+ return;
274
+ }
275
+
276
+ // Validate this job is holding all queues it needs
277
+ for (let i = 0; i < job.keys.length; i++) {
278
+ const queue = this.getQueue(job.keys[i]);
279
+ if (queue.active !== job) {
280
+ // This should never happen
281
+ return this.endJob(job, [
282
+ new BetterLockInternalError(
283
+ this.options.name,
284
+ `Corrupted wait queue state for ${queue.key}`
285
+ ),
286
+ ]);
287
+ }
288
+ }
289
+
290
+ // Mark job as having started executing
291
+ job.executed_at = new Date();
292
+
293
+ if (tools.isNumber(job.options.execution_timeout)) {
294
+ job.execution_timeout_id = setTimeout(
295
+ () => this.onExecutionTimeout(job),
296
+ job.options.execution_timeout
297
+ );
298
+ }
299
+
300
+ const lockDone = (...args) => {
301
+ this.log(`Done called for ${job}`);
302
+
303
+ this.endJob(job, args);
304
+ };
305
+
306
+ if (job.executor.length > 0) {
307
+ // Callback interface
308
+ job.executor(lockDone);
309
+ return;
310
+ }
311
+
312
+ // Promise interface
313
+ let executorResult;
314
+ try {
315
+ executorResult = (job.executor as any)();
316
+ } catch (err) {
317
+ // Error thrown directly from executor
318
+ lockDone(err);
319
+ }
320
+
321
+ // Promise sniffing
322
+ if (this.options.promise_tester(executorResult)) {
323
+ executorResult.then(
324
+ res => lockDone(null, res),
325
+ err => lockDone(err)
326
+ );
327
+ } else {
328
+ // "promise" is just some random value. We don't have to wait
329
+ lockDone(null, executorResult);
330
+ }
331
+ });
332
+ }
333
+
334
+ private onWaitTimeout(job: LockJob<any>) {
335
+ this.log(
336
+ `${job} has timed out after waiting in queue for ${
337
+ new Date().valueOf() - job.enqueued_at.valueOf()
338
+ }ms`
339
+ );
340
+
341
+ this.endJob(job, [new BetterLockWaitTimeoutError(this.options.name, job)]);
342
+ }
343
+
344
+ private onExecutionTimeout(job: LockJob<any>) {
345
+ this.log(
346
+ `${job} has timed out after executing for ${
347
+ new Date().valueOf() - job.executed_at.valueOf()
348
+ }ms`
349
+ );
350
+
351
+ this.endJob(job, [new BetterLockExecutionTimeoutError(this.options.name, job)]);
352
+ }
353
+
354
+ private endJob(job: LockJob<any>, callbackArgs: any[]) {
355
+ if (job.ended_at) {
356
+ this.log(
357
+ `WARNING: ${job} is trying to end, but it has already ended at ${job.ended_at.toISOString()}. Called with arguments: ${callbackArgs}`
358
+ );
359
+ return;
360
+ }
361
+
362
+ clearTimeout(job.wait_timeout_id);
363
+ job.wait_timeout_id = null;
364
+
365
+ clearTimeout(job.execution_timeout_id);
366
+ job.execution_timeout_id = null;
367
+
368
+ job.ended_at = new Date();
369
+
370
+ const queuesToUpdate = [];
371
+ for (let i = 0; i < job.keys.length; i++) {
372
+ const queue = this.getQueue(job.keys[i]);
373
+ queuesToUpdate.push(queue);
374
+
375
+ if (queue.active === job) {
376
+ // This job was holding on the queue's key
377
+ queue.active = null;
378
+ } else {
379
+ // This job was still in wait list for this queue
380
+ const index = queue.jobs.indexOf(job);
381
+ if (index >= 0) {
382
+ // Remove from queue
383
+ queue.jobs.splice(index, 1);
384
+ } else {
385
+ // Something is wrong. Where did this job come from?
386
+ this.log(
387
+ `WARNING: ${job} is ending, but it is not found anywhere in the queue for ${queue.key}`
388
+ );
389
+ }
390
+ }
391
+ }
392
+
393
+ // Call the callback
394
+ try {
395
+ job.callback.apply(null, callbackArgs);
396
+ } finally {
397
+ // Whatever happens, schedule a queue update
398
+ setImmediate(() => this.update(queuesToUpdate));
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Abort all jobs for a given key (or from the default job queue, if no key is given).
404
+ * Job executors will not be called. Callbacks will be called with JobAbortedError.
405
+ * Currently executing job will not be interrupted.
406
+ * @param [key]
407
+ */
408
+ public abort(key?: ILockKey) {
409
+ const queue = this.getQueue(key);
410
+ queue.jobs.slice().forEach(job => {
411
+ this.endJob(job, [new BetterLockJobAbortedError(this.options.name, job)]);
412
+ });
413
+ if (queue.active && !queue.active.executed_at) {
414
+ // If we have a job holding this queue that hasn't been executed yet, abort it as well
415
+ this.endJob(queue.active, [new BetterLockJobAbortedError(this.options.name, queue.active)]);
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Abort all pending jobs from all queues.
421
+ * Currently executing jobs will not be interrupted.
422
+ */
423
+ public abortAll() {
424
+ this.abort(null);
425
+ for (const key in this.queues) {
426
+ // noinspection JSUnfilteredForInLoop
427
+ this.abort(key);
428
+ }
429
+ }
430
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,124 @@
1
+ import { KeyQueue, LockJob } from './internals';
2
+ import { IErrorName } from './types';
3
+
4
+ export class BetterLockError extends Error {
5
+ /**
6
+ * Name of the lock that caused the error
7
+ */
8
+ lock_name: string;
9
+
10
+ /**
11
+ * Error name, maps to error's class name. Eg. BetterLockError.
12
+ */
13
+ name: IErrorName;
14
+
15
+ constructor(lockName, message, incomingStack = null) {
16
+ // Fix typescript custom Error prototype chain
17
+ // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
18
+ // https://github.com/reduardo7/ts-base-error/blob/master/src/index.ts
19
+ const trueProto = new.target.prototype;
20
+
21
+ if (lockName) {
22
+ super(`[${lockName}] ${message}`);
23
+ } else {
24
+ super(message);
25
+ }
26
+
27
+ Object.setPrototypeOf(this, trueProto);
28
+
29
+ this.lock_name = lockName;
30
+ this.name = this.constructor.name as IErrorName;
31
+
32
+ if (incomingStack) {
33
+ const withoutFirstLine = incomingStack.split('\n').slice(1).join('\n');
34
+ this.stack =
35
+ this.stack +
36
+ '\n --------------------------------------------------------------------------------\n' +
37
+ withoutFirstLine;
38
+ }
39
+ }
40
+ }
41
+
42
+ export class BetterLockInternalError extends BetterLockError {
43
+ constructor(lockName, message) {
44
+ const lastChar = message[message.length - 1];
45
+ if (lastChar !== '.' && lastChar !== '!' && lastChar !== '?') {
46
+ message += '.';
47
+ }
48
+ super(lockName, message + ' This is probably a bug inside "better-lock" library');
49
+ }
50
+ }
51
+
52
+ export class BetterLockInvalidArgumentError extends BetterLockError {
53
+ constructor(lockName, public argument, expected, actual) {
54
+ super(lockName, `Argument "${argument}" must be ${expected} (got: "${actual}")`);
55
+ this.argument = argument;
56
+ }
57
+ }
58
+
59
+ export class BetterLockWaitTimeoutError extends BetterLockError {
60
+ public job_id: number;
61
+ public keys: string[];
62
+ public enqueued_at: Date;
63
+
64
+ constructor(lockName, job: LockJob<any>) {
65
+ const message = `${job} has timed out after ${
66
+ new Date().valueOf() - job.enqueued_at.valueOf()
67
+ }ms in wait queue`;
68
+
69
+ super(lockName, message, job.incoming_stack);
70
+
71
+ this.job_id = job.id;
72
+ this.keys = job.keys;
73
+ this.enqueued_at = job.enqueued_at;
74
+ }
75
+ }
76
+
77
+ export class BetterLockExecutionTimeoutError extends BetterLockError {
78
+ public job_id: number;
79
+ public keys: string[];
80
+ public executed_at: Date;
81
+
82
+ constructor(lockName, job: LockJob<any>) {
83
+ const message = `${job} has timed out after ${
84
+ new Date().valueOf() - job.executed_at.valueOf()
85
+ }ms of execution`;
86
+
87
+ super(lockName, message, job.incoming_stack);
88
+
89
+ this.job_id = job.id;
90
+ this.keys = job.keys;
91
+ this.executed_at = job.executed_at;
92
+ }
93
+ }
94
+
95
+ export class BetterLockQueueOverflowError extends BetterLockError {
96
+ public job_id: number;
97
+ public keys: string[];
98
+ public job_count: number;
99
+ public kicked_out_job_id: number;
100
+
101
+ constructor(lockName, key, count, job: LockJob<any>) {
102
+ const keyDesignation = key === KeyQueue.DEFAULT_QUEUE_KEY ? '' : ` for key "${key}"`;
103
+ const message = `Too many jobs (${count}) are waiting${keyDesignation}. The most recent job (${job}) was kicked out`;
104
+
105
+ super(lockName, message, job.incoming_stack);
106
+
107
+ this.job_id = job.id;
108
+ this.keys = job.keys;
109
+ this.job_count = count;
110
+ this.kicked_out_job_id = job.id;
111
+ }
112
+ }
113
+
114
+ export class BetterLockJobAbortedError extends BetterLockError {
115
+ public job_id: number;
116
+ public keys: string[];
117
+
118
+ constructor(lockName, job) {
119
+ super(lockName, `${job} has been aborted by the user`, job.incoming_stack);
120
+
121
+ this.job_id = job.id;
122
+ this.keys = job.keys;
123
+ }
124
+ }
package/src/index.ts ADDED
@@ -0,0 +1,54 @@
1
+ import { BetterLock as BetterLockUnadorned } from './better_lock';
2
+ import {
3
+ BetterLockError,
4
+ BetterLockExecutionTimeoutError,
5
+ BetterLockInternalError,
6
+ BetterLockInvalidArgumentError,
7
+ BetterLockJobAbortedError,
8
+ BetterLockQueueOverflowError,
9
+ BetterLockWaitTimeoutError,
10
+ } from './errors';
11
+ import { ILockJobOptions as BetterLockJobOptions, IOptions as BetterLockOptions } from './options';
12
+ import {
13
+ IErrorName as BetterLockErrorName,
14
+ IExecutor as BetterLockExecutor,
15
+ ILockKey as BetterLockKey,
16
+ } from './types';
17
+
18
+ export {
19
+ BetterLockOptions,
20
+ BetterLockJobOptions,
21
+ BetterLockExecutor,
22
+ BetterLockKey,
23
+ BetterLockErrorName,
24
+ // Errors
25
+ BetterLockError,
26
+ BetterLockExecutionTimeoutError,
27
+ BetterLockInternalError,
28
+ BetterLockInvalidArgumentError,
29
+ BetterLockJobAbortedError,
30
+ BetterLockQueueOverflowError,
31
+ BetterLockWaitTimeoutError,
32
+ };
33
+
34
+ function attachExports<TTarget, TExports extends { [key: string]: any }>(
35
+ target: TTarget,
36
+ exports: TExports
37
+ ): TTarget & TExports {
38
+ Object.assign(target, exports);
39
+ return target as any;
40
+ }
41
+
42
+ export const BetterLock = attachExports(BetterLockUnadorned, {
43
+ BetterLock: BetterLockUnadorned,
44
+
45
+ Error: BetterLockError,
46
+ InternalError: BetterLockInternalError,
47
+ InvalidArgumentError: BetterLockInvalidArgumentError,
48
+ WaitTimeoutError: BetterLockWaitTimeoutError,
49
+ ExecutionTimeoutError: BetterLockExecutionTimeoutError,
50
+ QueueOverflowError: BetterLockQueueOverflowError,
51
+ JobAbortedError: BetterLockJobAbortedError,
52
+ });
53
+
54
+ export default BetterLock;