better-lock 2.0.3 → 3.1.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.
Files changed (52) hide show
  1. package/.idea/prettier.xml +1 -0
  2. package/README.md +55 -41
  3. package/dist/better_lock.js +38 -35
  4. package/dist/better_lock.js.map +1 -1
  5. package/dist/errors.d.ts +3 -1
  6. package/dist/errors.js +11 -12
  7. package/dist/errors.js.map +1 -1
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js.map +1 -1
  10. package/dist/internals.js +2 -2
  11. package/dist/internals.js.map +1 -1
  12. package/dist/options.d.ts +17 -0
  13. package/dist/types.d.ts +1 -1
  14. package/docs/assets/highlight.css +3 -3
  15. package/docs/assets/main.js +4 -2
  16. package/docs/assets/search.js +1 -1
  17. package/docs/assets/style.css +424 -538
  18. package/docs/classes/BetterLockError.html +109 -5
  19. package/docs/classes/BetterLockExecutionTimeoutError.html +122 -5
  20. package/docs/classes/BetterLockInternalError.html +101 -5
  21. package/docs/classes/BetterLockInvalidArgumentError.html +112 -5
  22. package/docs/classes/BetterLockJobAbortedError.html +115 -5
  23. package/docs/classes/BetterLockQueueOverflowError.html +142 -5
  24. package/docs/classes/BetterLockWaitTimeoutError.html +122 -5
  25. package/docs/classes/_internal_.BetterLock.html +297 -65
  26. package/docs/classes/_internal_.KeyQueue.html +126 -7
  27. package/docs/classes/_internal_.LockJob.html +225 -27
  28. package/docs/index.html +83 -13
  29. package/docs/interfaces/BetterLockJobOptions.html +89 -9
  30. package/docs/interfaces/BetterLockOptions.html +149 -17
  31. package/docs/modules/_internal_.__home_panta_dev_pantas_better_lock_src_errors_.html +80 -1
  32. package/docs/modules/_internal_.html +68 -7
  33. package/docs/modules.html +96 -5
  34. package/docs/types/BetterLockErrorName.html +61 -0
  35. package/docs/types/BetterLockExecutor.html +63 -0
  36. package/docs/types/BetterLockKey.html +61 -0
  37. package/docs/types/BetterLockQueueEjectionStrategy.html +59 -0
  38. package/docs/types/_internal_.ICallback.html +59 -0
  39. package/docs/types/_internal_.ICallbackExecutor.html +73 -0
  40. package/docs/types/_internal_.IErrorExports.html +52 -0
  41. package/docs/types/_internal_.IPromiseExecutor.html +65 -0
  42. package/docs/variables/BetterLock.html +59 -0
  43. package/package.json +6 -6
  44. package/spec/better_lock.spec.ts +97 -1
  45. package/src/better_lock.ts +33 -28
  46. package/src/errors.ts +5 -2
  47. package/src/index.ts +2 -1
  48. package/src/options.ts +22 -0
  49. package/src/types.ts +2 -2
  50. package/docs/assets/icons.css +0 -1043
  51. package/docs/assets/icons.png +0 -0
  52. package/docs/assets/icons@2x.png +0 -0
@@ -0,0 +1,59 @@
1
+ <!DOCTYPE html><html class="default"><head><meta charSet="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>BetterLock | better-lock</title><meta name="description" content="Documentation for better-lock"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script async src="../assets/search.js" id="search-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os"</script><header class="tsd-page-toolbar">
2
+ <div class="tsd-toolbar-contents container">
3
+ <div class="table-cell" id="tsd-search" data-base="..">
4
+ <div class="field"><label for="tsd-search-field" class="tsd-widget search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M15.7824 13.833L12.6666 10.7177C12.5259 10.5771 12.3353 10.499 12.1353 10.499H11.6259C12.4884 9.39596 13.001 8.00859 13.001 6.49937C13.001 2.90909 10.0914 0 6.50048 0C2.90959 0 0 2.90909 0 6.49937C0 10.0896 2.90959 12.9987 6.50048 12.9987C8.00996 12.9987 9.39756 12.4863 10.5008 11.6239V12.1332C10.5008 12.3332 10.5789 12.5238 10.7195 12.6644L13.8354 15.7797C14.1292 16.0734 14.6042 16.0734 14.8948 15.7797L15.7793 14.8954C16.0731 14.6017 16.0731 14.1267 15.7824 13.833ZM6.50048 10.499C4.29094 10.499 2.50018 8.71165 2.50018 6.49937C2.50018 4.29021 4.28781 2.49976 6.50048 2.49976C8.71001 2.49976 10.5008 4.28708 10.5008 6.49937C10.5008 8.70852 8.71314 10.499 6.50048 10.499Z" fill="var(--color-text)"></path></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div>
5
+ <ul class="results">
6
+ <li class="state loading">Preparing search index...</li>
7
+ <li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">better-lock</a></div>
8
+ <div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="1" y="3" width="14" height="2" fill="var(--color-text)"></rect><rect x="1" y="7" width="14" height="2" fill="var(--color-text)"></rect><rect x="1" y="11" width="14" height="2" fill="var(--color-text)"></rect></svg></a></div></div></header>
9
+ <div class="container container-main">
10
+ <div class="col-8 col-content">
11
+ <div class="tsd-page-title">
12
+ <ul class="tsd-breadcrumb">
13
+ <li><a href="../modules.html">better-lock</a></li>
14
+ <li><a href="BetterLock.html">BetterLock</a></li></ul>
15
+ <h1>Variable BetterLock<code class="tsd-tag ts-flagConst">Const</code> </h1></div>
16
+ <div class="tsd-signature">Better<wbr/>Lock<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol">typeof </span><a href="../modules/_internal_.html" class="tsd-signature-type" data-tsd-kind="Namespace">&lt;internal&gt;</a><span class="tsd-signature-symbol">.</span><a href="../classes/_internal_.BetterLock.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLock</a><span class="tsd-signature-symbol"> &amp; </span><span class="tsd-signature-symbol">{ </span>BetterLock<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">typeof </span><a href="../modules/_internal_.html" class="tsd-signature-type" data-tsd-kind="Namespace">&lt;internal&gt;</a><span class="tsd-signature-symbol">.</span><a href="../classes/_internal_.BetterLock.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLock</a><span class="tsd-signature-symbol">; </span>Error<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">typeof </span><a href="../classes/BetterLockError.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLockError</a><span class="tsd-signature-symbol">; </span>ExecutionTimeoutError<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">typeof </span><a href="../classes/BetterLockExecutionTimeoutError.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLockExecutionTimeoutError</a><span class="tsd-signature-symbol">; </span>InternalError<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">typeof </span><a href="../classes/BetterLockInternalError.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLockInternalError</a><span class="tsd-signature-symbol">; </span>InvalidArgumentError<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">typeof </span><a href="../classes/BetterLockInvalidArgumentError.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLockInvalidArgumentError</a><span class="tsd-signature-symbol">; </span>JobAbortedError<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">typeof </span><a href="../classes/BetterLockJobAbortedError.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLockJobAbortedError</a><span class="tsd-signature-symbol">; </span>QueueOverflowError<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">typeof </span><a href="../classes/BetterLockQueueOverflowError.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLockQueueOverflowError</a><span class="tsd-signature-symbol">; </span>WaitTimeoutError<span class="tsd-signature-symbol">: </span><span class="tsd-signature-symbol">typeof </span><a href="../classes/BetterLockWaitTimeoutError.html" class="tsd-signature-type" data-tsd-kind="Class">BetterLockWaitTimeoutError</a><span class="tsd-signature-symbol"> }</span><span class="tsd-signature-symbol"> = ...</span></div><aside class="tsd-sources">
17
+ <ul>
18
+ <li>Defined in <a href="https://github.com/panta82/better-lock/blob/336aa4f/src/index.ts#L43">index.ts:43</a></li></ul></aside></div>
19
+ <div class="col-4 col-menu menu-sticky-wrap menu-highlight">
20
+ <div class="tsd-navigation settings">
21
+ <details class="tsd-index-accordion"><summary class="tsd-accordion-summary">
22
+ <h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M4.93896 8.531L12 15.591L19.061 8.531L16.939 6.409L12 11.349L7.06098 6.409L4.93896 8.531Z" fill="var(--color-text)"></path></svg> Settings</h3></summary>
23
+ <div class="tsd-accordion-details">
24
+ <div class="tsd-filter-visibility">
25
+ <h4 class="uppercase">Member Visibility</h4><form>
26
+ <ul id="tsd-filter-options">
27
+ <li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></form></div>
28
+ <div class="tsd-theme-toggle">
29
+ <h4 class="uppercase">Theme</h4><select id="theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div>
30
+ <nav class="tsd-navigation primary">
31
+ <details class="tsd-index-accordion" open><summary class="tsd-accordion-summary">
32
+ <h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M4.93896 8.531L12 15.591L19.061 8.531L16.939 6.409L12 11.349L7.06098 6.409L4.93896 8.531Z" fill="var(--color-text)"></path></svg> Modules</h3></summary>
33
+ <div class="tsd-accordion-details">
34
+ <ul>
35
+ <li><a href="../modules.html">better-<wbr/>lock</a>
36
+ <ul>
37
+ <li class="tsd-kind-namespace"><a href="../modules/_internal_.html">&lt;internal&gt;</a>
38
+ <ul>
39
+ <li class="tsd-kind-namespace tsd-parent-kind-namespace"><a href="../modules/_internal_.__home_panta_dev_pantas_better_lock_src_errors_.html">&quot;/home/panta/dev/pantas/better-<wbr/>lock/src/errors&quot;</a></li></ul></li></ul></li></ul></div></details></nav>
40
+ <nav class="tsd-navigation secondary menu-sticky">
41
+ <ul>
42
+ <li class="tsd-kind-reference"><a href="../modules.html#default" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><rect fill="var(--color-icon-background)" stroke="#FF4D82" stroke-width="1.5" x="1" y="1" width="22" height="22" rx="12" id="icon-8388608-path"></rect><path d="M10.354 17V8.24H13.066C13.586 8.24 14.042 8.348 14.434 8.564C14.826 8.772 15.13 9.064 15.346 9.44C15.562 9.816 15.67 10.256 15.67 10.76C15.67 11.352 15.514 11.86 15.202 12.284C14.898 12.708 14.482 13 13.954 13.16L15.79 17H14.518L12.838 13.28H11.434V17H10.354ZM11.434 12.308H13.066C13.514 12.308 13.874 12.168 14.146 11.888C14.418 11.6 14.554 11.224 14.554 10.76C14.554 10.288 14.418 9.912 14.146 9.632C13.874 9.352 13.514 9.212 13.066 9.212H11.434V12.308Z" fill="var(--color-text)" id="icon-8388608-text"></path></svg>default</a></li>
43
+ <li class="tsd-kind-class"><a href="../classes/BetterLockError.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><rect fill="var(--color-icon-background)" stroke="var(--color-ts-class)" stroke-width="1.5" x="1" y="1" width="22" height="22" rx="6" id="icon-128-path"></rect><path d="M11.898 16.1201C11.098 16.1201 10.466 15.8961 10.002 15.4481C9.53803 15.0001 9.30603 14.3841 9.30603 13.6001V9.64012C9.30603 8.85612 9.53803 8.24012 10.002 7.79212C10.466 7.34412 11.098 7.12012 11.898 7.12012C12.682 7.12012 13.306 7.34812 13.77 7.80412C14.234 8.25212 14.466 8.86412 14.466 9.64012H13.386C13.386 9.14412 13.254 8.76412 12.99 8.50012C12.734 8.22812 12.37 8.09212 11.898 8.09212C11.426 8.09212 11.054 8.22412 10.782 8.48812C10.518 8.75212 10.386 9.13212 10.386 9.62812V13.6001C10.386 14.0961 10.518 14.4801 10.782 14.7521C11.054 15.0161 11.426 15.1481 11.898 15.1481C12.37 15.1481 12.734 15.0161 12.99 14.7521C13.254 14.4801 13.386 14.0961 13.386 13.6001H14.466C14.466 14.3761 14.234 14.9921 13.77 15.4481C13.306 15.8961 12.682 16.1201 11.898 16.1201Z" fill="var(--color-text)" id="icon-128-text"></path></svg>Better<wbr/>Lock<wbr/>Error</a></li>
44
+ <li class="tsd-kind-class"><a href="../classes/BetterLockExecutionTimeoutError.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-128-path"></use><use href="#icon-128-text"></use></svg>Better<wbr/>Lock<wbr/>Execution<wbr/>Timeout<wbr/>Error</a></li>
45
+ <li class="tsd-kind-class"><a href="../classes/BetterLockInternalError.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-128-path"></use><use href="#icon-128-text"></use></svg>Better<wbr/>Lock<wbr/>Internal<wbr/>Error</a></li>
46
+ <li class="tsd-kind-class"><a href="../classes/BetterLockInvalidArgumentError.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-128-path"></use><use href="#icon-128-text"></use></svg>Better<wbr/>Lock<wbr/>Invalid<wbr/>Argument<wbr/>Error</a></li>
47
+ <li class="tsd-kind-class"><a href="../classes/BetterLockJobAbortedError.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-128-path"></use><use href="#icon-128-text"></use></svg>Better<wbr/>Lock<wbr/>Job<wbr/>Aborted<wbr/>Error</a></li>
48
+ <li class="tsd-kind-class"><a href="../classes/BetterLockQueueOverflowError.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-128-path"></use><use href="#icon-128-text"></use></svg>Better<wbr/>Lock<wbr/>Queue<wbr/>Overflow<wbr/>Error</a></li>
49
+ <li class="tsd-kind-class"><a href="../classes/BetterLockWaitTimeoutError.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-128-path"></use><use href="#icon-128-text"></use></svg>Better<wbr/>Lock<wbr/>Wait<wbr/>Timeout<wbr/>Error</a></li>
50
+ <li class="tsd-kind-interface"><a href="../interfaces/BetterLockJobOptions.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><rect fill="var(--color-icon-background)" stroke="var(--color-ts-interface)" stroke-width="1.5" x="1" y="1" width="22" height="22" rx="6" id="icon-256-path"></rect><path d="M9.51 16V15.016H11.298V8.224H9.51V7.24H14.19V8.224H12.402V15.016H14.19V16H9.51Z" fill="var(--color-text)" id="icon-256-text"></path></svg>Better<wbr/>Lock<wbr/>Job<wbr/>Options</a></li>
51
+ <li class="tsd-kind-interface"><a href="../interfaces/BetterLockOptions.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-256-path"></use><use href="#icon-256-text"></use></svg>Better<wbr/>Lock<wbr/>Options</a></li>
52
+ <li class="tsd-kind-type-alias"><a href="../types/BetterLockErrorName.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><rect fill="var(--color-icon-background)" stroke="var(--color-ts)" stroke-width="1.5" x="1" y="1" width="22" height="22" rx="6" id="icon-4194304-path"></rect><path d="M11.31 16V8.224H8.91V7.24H14.79V8.224H12.39V16H11.31Z" fill="var(--color-text)" id="icon-4194304-text"></path></svg>Better<wbr/>Lock<wbr/>Error<wbr/>Name</a></li>
53
+ <li class="tsd-kind-type-alias"><a href="../types/BetterLockExecutor.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-4194304-path"></use><use href="#icon-4194304-text"></use></svg>Better<wbr/>Lock<wbr/>Executor</a></li>
54
+ <li class="tsd-kind-type-alias"><a href="../types/BetterLockKey.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-4194304-path"></use><use href="#icon-4194304-text"></use></svg>Better<wbr/>Lock<wbr/>Key</a></li>
55
+ <li class="tsd-kind-type-alias"><a href="../types/BetterLockQueueEjectionStrategy.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><use href="#icon-4194304-path"></use><use href="#icon-4194304-text"></use></svg>Better<wbr/>Lock<wbr/>Queue<wbr/>Ejection<wbr/>Strategy</a></li>
56
+ <li class="current tsd-kind-variable"><a href="BetterLock.html" class="tsd-index-link"><svg class="tsd-kind-icon" width="24" height="24" viewBox="0 0 24 24"><rect fill="var(--color-icon-background)" stroke="var(--color-ts-variable)" stroke-width="1.5" x="1" y="1" width="22" height="22" rx="6" id="icon-32-path"></rect><path d="M11.106 16L8.85 7.24H9.966L11.454 13.192C11.558 13.608 11.646 13.996 11.718 14.356C11.79 14.708 11.842 14.976 11.874 15.16C11.906 14.976 11.954 14.708 12.018 14.356C12.09 13.996 12.178 13.608 12.282 13.192L13.758 7.24H14.85L12.582 16H11.106Z" fill="var(--color-text)" id="icon-32-text"></path></svg>Better<wbr/>Lock</a></li></ul></nav></div></div>
57
+ <div class="container tsd-generator">
58
+ <p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></div>
59
+ <div class="overlay"></div><script src="../assets/main.js"></script></body></html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-lock",
3
- "version": "2.0.3",
3
+ "version": "3.1.0",
4
4
  "description": "A (better) node.js lock library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,18 +27,18 @@
27
27
  "sync"
28
28
  ],
29
29
  "devDependencies": {
30
- "@types/jest": "^27.5.1",
30
+ "@types/jest": "29",
31
31
  "@typescript-eslint/eslint-plugin": "^4.25.0",
32
32
  "@typescript-eslint/parser": "^4.25.0",
33
33
  "eslint": "^7.27.0",
34
34
  "eslint-config-prettier": "^8.3.0",
35
35
  "import-sort-style-module": "^6.0.0",
36
- "jest": "^28.1.0",
36
+ "jest": "29",
37
37
  "prettier": "latest",
38
38
  "prettier-plugin-import-sort": "0.0.7",
39
- "ts-jest": "^28.0.3",
40
- "typedoc": "^0.22.15",
41
- "typedoc-plugin-missing-exports": "^0.22.6",
39
+ "ts-jest": "29",
40
+ "typedoc": "0.23.0",
41
+ "typedoc-plugin-missing-exports": "0.23.0",
42
42
  "typescript": "^4.3.2"
43
43
  },
44
44
  "author": "Ivan Pantic",
@@ -1,5 +1,6 @@
1
1
  import BetterLock from '../src/index';
2
2
  import { LockJob } from '../src/internals';
3
+ import { ILockJobOptions } from '../src/options';
3
4
 
4
5
  describe('BetterLock', () => {
5
6
  let baseDefaultOptions;
@@ -254,13 +255,48 @@ describe('BetterLock', () => {
254
255
  });
255
256
 
256
257
  describe('when overflowing', () => {
257
- it('it will kick out the most recently submitted job', testDone => {
258
+ it('it will kick out the correct job using the default "oldest" strategy', testDone => {
258
259
  const lock = new BetterLock({
259
260
  wait_timeout: 200, // should never trigger
260
261
  execution_timeout: 300, // should never trigger
261
262
  queue_size: 2,
262
263
  });
263
264
 
265
+ let cbCount = 0;
266
+ lock.acquire(waitCallback(25, 1), arg => {
267
+ // The executing one
268
+ cbCount++;
269
+ expect(cbCount).toEqual(2);
270
+ expect(arg).toEqual(1);
271
+ });
272
+ lock.acquire(waitCallback(5, 2), err => {
273
+ // This is the one that will get kicked out
274
+ cbCount++;
275
+ expect(cbCount).toEqual(1);
276
+ expect(err).toBeInstanceOf(BetterLock.QueueOverflowError);
277
+ });
278
+ lock.acquire(waitCallback(5, 3), arg => {
279
+ cbCount++;
280
+ expect(cbCount).toEqual(3);
281
+ expect(arg).toEqual(3);
282
+ testDone();
283
+ });
284
+ lock.acquire(waitCallback(5, 4), arg => {
285
+ // This one will trigger the kicking out.
286
+ cbCount++;
287
+ expect(cbCount).toEqual(4);
288
+ expect(arg).toEqual(4);
289
+ });
290
+ });
291
+
292
+ it('it will kick out the correct job using the "newest" strategy', testDone => {
293
+ const lock = new BetterLock({
294
+ wait_timeout: 200, // should never trigger
295
+ execution_timeout: 300, // should never trigger
296
+ queue_size: 2,
297
+ queue_ejection_strategy: 'newest',
298
+ });
299
+
264
300
  let cbCount = 0;
265
301
  lock.acquire(waitCallback(25, 1), arg => {
266
302
  // The executing one
@@ -310,6 +346,7 @@ describe('BetterLock', () => {
310
346
  wait_timeout: 0,
311
347
  execution_timeout: 5,
312
348
  queue_size: 1,
349
+ queue_ejection_strategy: 'newest',
313
350
  });
314
351
 
315
352
  return Promise.all([
@@ -590,6 +627,65 @@ describe('BetterLock', () => {
590
627
  });
591
628
  });
592
629
  });
630
+
631
+ describe('will respect lock_condition', () => {
632
+ function runJob(
633
+ lock: InstanceType<typeof BetterLock>,
634
+ key: string,
635
+ expectedMs: number,
636
+ options?: ILockJobOptions
637
+ ) {
638
+ const startedAt = new Date();
639
+ let executed = false;
640
+ return lock
641
+ .acquire(
642
+ key,
643
+ () => {
644
+ executed = true;
645
+ expectMs(new Date().valueOf() - startedAt.valueOf(), expectedMs);
646
+ return waitPromise(50);
647
+ },
648
+ options
649
+ )
650
+ .finally(() => {
651
+ expect(executed).toBeTruthy();
652
+ });
653
+ }
654
+
655
+ it('for global condition', async () => {
656
+ const lock = new BetterLock({
657
+ lock_condition: key => !String(key).startsWith('a'),
658
+ });
659
+
660
+ await Promise.all([
661
+ runJob(lock, 'a', 0),
662
+ runJob(lock, 'a', 0),
663
+ runJob(lock, 'a', 0),
664
+ runJob(lock, 'b', 0),
665
+ runJob(lock, 'b', 50),
666
+ runJob(lock, 'b', 100),
667
+ ]);
668
+ });
669
+
670
+ it('for local condition', async () => {
671
+ const lock = new BetterLock({
672
+ lock_condition: key => !String(key).startsWith('a'),
673
+ });
674
+
675
+ const overrideToB = {
676
+ lock_condition: key => !String(key).startsWith('b'),
677
+ };
678
+
679
+ await Promise.all([
680
+ runJob(lock, 'b', 0, overrideToB),
681
+ runJob(lock, 'b', 0, overrideToB),
682
+ runJob(lock, 'b', 0, overrideToB),
683
+ runJob(lock, 'a', 0, overrideToB),
684
+ runJob(lock, 'a', 50, overrideToB),
685
+ runJob(lock, 'a', 100, overrideToB),
686
+ ]);
687
+ });
688
+ });
593
689
  });
594
690
 
595
691
  function waitCallback(ms: number, ...args): (done: (...args: any) => void) => void {
@@ -133,23 +133,6 @@ export class BetterLock {
133
133
  key = null;
134
134
  }
135
135
 
136
- // Repackage "key" into an array of keys
137
- const keys = [];
138
- if (Array.isArray(key)) {
139
- const arrayOfKeys = key;
140
- // Make sure we don't add duplicates
141
- const seenKeys = new Set();
142
- for (let i = 0; i < arrayOfKeys.length; i++) {
143
- const normalizedKey = this.normalizeAndValidateKey(arrayOfKeys[i]);
144
- if (!seenKeys.has(normalizedKey)) {
145
- keys.push(normalizedKey);
146
- seenKeys.add(normalizedKey);
147
- }
148
- }
149
- } else {
150
- keys.push(this.normalizeAndValidateKey(key));
151
- }
152
-
153
136
  // Create callback wrapper for promise interface
154
137
  if (!tools.isFunction(callback)) {
155
138
  if (jobOptions === undefined) {
@@ -159,6 +142,32 @@ export class BetterLock {
159
142
  callback = tools.callbackWithPromise();
160
143
  }
161
144
 
145
+ // Prepare job options
146
+ const effectiveJobOptions = jobOptions
147
+ ? tools.assign({} as IOptions, [this.options, jobOptions])
148
+ : // No need to create new object since these will be read-only and are subset of global options
149
+ this.options;
150
+
151
+ // Repackage "key" into an array of keys, but only if lock_condition allows it.
152
+ // Otherwise, it stays an array and gets executed immediately.
153
+ const keys = [];
154
+ if (!effectiveJobOptions.lock_condition || effectiveJobOptions.lock_condition(key)) {
155
+ if (Array.isArray(key)) {
156
+ const arrayOfKeys = key;
157
+ // Make sure we don't add duplicates
158
+ const seenKeys = new Set();
159
+ for (let i = 0; i < arrayOfKeys.length; i++) {
160
+ const normalizedKey = this.normalizeAndValidateKey(arrayOfKeys[i]);
161
+ if (!seenKeys.has(normalizedKey)) {
162
+ keys.push(normalizedKey);
163
+ seenKeys.add(normalizedKey);
164
+ }
165
+ }
166
+ } else {
167
+ keys.push(this.normalizeAndValidateKey(key));
168
+ }
169
+ }
170
+
162
171
  // Validate other options
163
172
  if (!tools.isFunction(executor)) {
164
173
  throw new BetterLockInvalidArgumentError(
@@ -177,12 +186,6 @@ export class BetterLock {
177
186
  );
178
187
  }
179
188
 
180
- // Prepare job options
181
- const effectiveJobOptions = jobOptions
182
- ? tools.assign({}, [this.options, jobOptions])
183
- : // No need to create new object since these will be read-only and are subset of global options
184
- this.options;
185
-
186
189
  const job = new LockJob(keys, executor, callback, effectiveJobOptions);
187
190
 
188
191
  // Set incoming stack
@@ -242,18 +245,20 @@ export class BetterLock {
242
245
 
243
246
  // Handle wait queue overflow
244
247
  if (tools.isNumber(this.options.queue_size) && this.options.queue_size < queue.jobs.length) {
245
- // Overflow. Reject the most recent job
246
- const mostRecentJob = queue.jobs[queue.jobs.length - 1];
248
+ const strategy = this.options.queue_ejection_strategy || 'oldest';
249
+
250
+ const targetJob = queue.jobs[strategy === 'oldest' ? 0 : queue.jobs.length - 1];
247
251
  this.log(
248
- `${queue.toString()} has overflown, so most recent job (${mostRecentJob}) was kicked out`
252
+ `${queue.toString()} has overflown, so the ${strategy} job (${targetJob}) was kicked out`
249
253
  );
250
254
 
251
- this.endJob(mostRecentJob, [
255
+ this.endJob(targetJob, [
252
256
  new BetterLockQueueOverflowError(
253
257
  this.options.name,
254
258
  queue.key,
255
259
  queue.jobs.length,
256
- mostRecentJob
260
+ targetJob,
261
+ strategy
257
262
  ),
258
263
  ]);
259
264
  }
package/src/errors.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { KeyQueue, LockJob } from './internals';
2
2
  import { IErrorName } from './types';
3
+ import { IQueueEjectionStrategy } from './options';
3
4
 
4
5
  export class BetterLockError extends Error {
5
6
  /**
@@ -97,10 +98,11 @@ export class BetterLockQueueOverflowError extends BetterLockError {
97
98
  public keys: string[];
98
99
  public job_count: number;
99
100
  public kicked_out_job_id: number;
101
+ public strategy: IQueueEjectionStrategy;
100
102
 
101
- constructor(lockName, key, count, job: LockJob<any>) {
103
+ constructor(lockName, key, count, job: LockJob<any>, strategy: IQueueEjectionStrategy) {
102
104
  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`;
105
+ const message = `Too many jobs (${count}) are waiting${keyDesignation}. The ${strategy} job (${job}) was kicked out`;
104
106
 
105
107
  super(lockName, message, job.incoming_stack);
106
108
 
@@ -108,6 +110,7 @@ export class BetterLockQueueOverflowError extends BetterLockError {
108
110
  this.keys = job.keys;
109
111
  this.job_count = count;
110
112
  this.kicked_out_job_id = job.id;
113
+ this.strategy = strategy;
111
114
  }
112
115
  }
113
116
 
package/src/index.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  BetterLockQueueOverflowError,
9
9
  BetterLockWaitTimeoutError,
10
10
  } from './errors';
11
- import { ILockJobOptions as BetterLockJobOptions, IOptions as BetterLockOptions } from './options';
11
+ import { ILockJobOptions as BetterLockJobOptions, IOptions as BetterLockOptions, IQueueEjectionStrategy as BetterLockQueueEjectionStrategy } from './options';
12
12
  import {
13
13
  IErrorName as BetterLockErrorName,
14
14
  IExecutor as BetterLockExecutor,
@@ -17,6 +17,7 @@ import {
17
17
 
18
18
  export {
19
19
  BetterLockOptions,
20
+ BetterLockQueueEjectionStrategy,
20
21
  BetterLockJobOptions,
21
22
  BetterLockExecutor,
22
23
  BetterLockKey,
package/src/options.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { ILockKey } from './types';
2
+
1
3
  /**
2
4
  * Options that apply on LockJob
3
5
  */
@@ -16,8 +18,17 @@ export interface ILockJobOptions {
16
18
  * In any error produced by BetterLock, extend the stack trace to include incoming trace. Overrides BetterLockOptions value.
17
19
  */
18
20
  extend_stack_traces?: boolean;
21
+
22
+ /**
23
+ * Before acquiring lock, call this function with the given key. If condition is rejected, the executor is immediately called, without locking.
24
+ * This can be used to more conveniently opt out of locking, without duplicating or extracting the executor.
25
+ * Overrides BetterLockOptions value.
26
+ */
27
+ lock_condition?: (key: ILockKey | Array<ILockKey>) => boolean;
19
28
  }
20
29
 
30
+ export type IQueueEjectionStrategy = 'oldest' | 'newest';
31
+
21
32
  /**
22
33
  * Options that apply on BetterLock instance
23
34
  */
@@ -38,6 +49,17 @@ export interface IOptions extends ILockJobOptions {
38
49
  */
39
50
  queue_size?: number | null;
40
51
 
52
+ /**
53
+ * If queue is full, which job to eject. Defaults to 'oldest'.
54
+ */
55
+ queue_ejection_strategy?: IQueueEjectionStrategy;
56
+
57
+ /**
58
+ * Before acquiring lock, call this function with the given key. If condition is rejected, the executor is immediately called, without locking.
59
+ * This can be used to more conveniently opt out of locking, without duplicating or extracting the executor.
60
+ */
61
+ lock_condition?: (key: ILockKey | Array<ILockKey>) => boolean;
62
+
41
63
  /**
42
64
  * Lock name. This will be written in all logs and error messages, to help you distinguish between different locks
43
65
  */
package/src/types.ts CHANGED
@@ -12,8 +12,8 @@ export type IErrorName = keyof IErrorExports;
12
12
  * but also old-school callbacks, with varargs return values.
13
13
  */
14
14
  export type ICallback<TResult> = TResult extends any[]
15
- ? (err?: Error, ...result: TResult) => void
16
- : (err?: Error, result?: TResult) => void;
15
+ ? (err: Error | null, ...result: TResult) => void
16
+ : (err: Error | null, result?: TResult) => void;
17
17
 
18
18
  /**
19
19
  * Function that user will supply as the thing that will be running inside lock.