@prairielearn/named-locks 1.4.0 → 1.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @prairielearn/named-locks
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - cdb0f2109: Add optional `onNotAcquired` function to `doWithLock` and `tryWithLock`
8
+
3
9
  ## 1.4.0
4
10
 
5
11
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -27,6 +27,9 @@ interface LockOptions {
27
27
  */
28
28
  autoRenew?: boolean;
29
29
  }
30
+ interface WithLockOptions<T> extends LockOptions {
31
+ onNotAcquired?: () => Promise<T> | T;
32
+ }
30
33
  export declare const pool: PostgresPool;
31
34
  /**
32
35
  * Initializes a new {@link PostgresPool} that will be used to acquire named locks.
@@ -64,12 +67,19 @@ export declare const releaseLock: (arg1: Lock, callback: (err: NodeJS.ErrnoExcep
64
67
  /**
65
68
  * Acquires the given lock, executes the provided function with the lock held,
66
69
  * and releases the lock once the function has executed.
70
+ *
71
+ * If the lock cannot be acquired, the function is not executed. If an `onNotAcquired`
72
+ * function was provided, this function is called and its return value is returned.
73
+ * Otherwise, an error is thrown to indicate that the lock could not be acquired.
67
74
  */
68
- export declare function doWithLock<T>(name: string, options: LockOptions, func: () => Promise<T>): Promise<T>;
75
+ export declare function doWithLock<T, U = never>(name: string, options: WithLockOptions<U>, func: () => Promise<T>): Promise<T | U>;
69
76
  /**
70
77
  * Tries to acquire the given lock, executes the provided function with the lock held,
71
- * and releases the lock once the function has executed. If the lock cannot be acquired,
72
- * the function is not executed and null is returned.
78
+ * and releases the lock once the function has executed.
79
+ *
80
+ * If the lock cannot be acquired, the function is not executed. If an `onNotAcquired`
81
+ * function was provided, this function is called and its return value is returned.
82
+ * Otherwise, `null` is returned.
73
83
  */
74
- export declare function tryWithLock<T>(name: string, options: LockOptions, func: () => Promise<T>): Promise<T | null>;
84
+ export declare function tryWithLock<T, U = null>(name: string, options: WithLockOptions<U>, func: () => Promise<T>): Promise<T | U>;
75
85
  export {};
package/dist/index.js CHANGED
@@ -109,9 +109,21 @@ exports.releaseLock = util_1.default.callbackify(releaseLockAsync);
109
109
  /**
110
110
  * Acquires the given lock, executes the provided function with the lock held,
111
111
  * and releases the lock once the function has executed.
112
+ *
113
+ * If the lock cannot be acquired, the function is not executed. If an `onNotAcquired`
114
+ * function was provided, this function is called and its return value is returned.
115
+ * Otherwise, an error is thrown to indicate that the lock could not be acquired.
112
116
  */
113
117
  async function doWithLock(name, options, func) {
114
- const lock = await waitLockAsync(name, options);
118
+ const lock = await tryLockAsync(name, options);
119
+ if (!lock) {
120
+ if (options.onNotAcquired) {
121
+ return await options.onNotAcquired();
122
+ }
123
+ else {
124
+ throw new Error(`failed to acquire lock: ${name}`);
125
+ }
126
+ }
115
127
  try {
116
128
  return await func();
117
129
  }
@@ -122,19 +134,17 @@ async function doWithLock(name, options, func) {
122
134
  exports.doWithLock = doWithLock;
123
135
  /**
124
136
  * Tries to acquire the given lock, executes the provided function with the lock held,
125
- * and releases the lock once the function has executed. If the lock cannot be acquired,
126
- * the function is not executed and null is returned.
137
+ * and releases the lock once the function has executed.
138
+ *
139
+ * If the lock cannot be acquired, the function is not executed. If an `onNotAcquired`
140
+ * function was provided, this function is called and its return value is returned.
141
+ * Otherwise, `null` is returned.
127
142
  */
128
143
  async function tryWithLock(name, options, func) {
129
- const lock = await tryLockAsync(name, options);
130
- if (lock == null)
131
- return null;
132
- try {
133
- return await func();
134
- }
135
- finally {
136
- await releaseLockAsync(lock);
137
- }
144
+ return await doWithLock(name, {
145
+ onNotAcquired: () => null,
146
+ ...options,
147
+ }, func);
138
148
  }
139
149
  exports.tryWithLock = tryWithLock;
140
150
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/named-locks",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "main": "./dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.ts CHANGED
@@ -19,6 +19,7 @@ interface Lock {
19
19
  interface LockOptions {
20
20
  /** How many milliseconds to wait (anything other than a positive number means forever) */
21
21
  timeout?: number;
22
+
22
23
  /**
23
24
  * Whether or not this lock should automatically renew itself periodically.
24
25
  * By default, locks will not renew themselves.
@@ -30,6 +31,10 @@ interface LockOptions {
30
31
  autoRenew?: boolean;
31
32
  }
32
33
 
34
+ interface WithLockOptions<T> extends LockOptions {
35
+ onNotAcquired?: () => Promise<T> | T;
36
+ }
37
+
33
38
  /*
34
39
  * The functions here all identify locks by "name", which is a plain
35
40
  * string. The locks use the named_locks DB table. Each lock name
@@ -143,13 +148,26 @@ export const releaseLock = util.callbackify(releaseLockAsync);
143
148
  /**
144
149
  * Acquires the given lock, executes the provided function with the lock held,
145
150
  * and releases the lock once the function has executed.
151
+ *
152
+ * If the lock cannot be acquired, the function is not executed. If an `onNotAcquired`
153
+ * function was provided, this function is called and its return value is returned.
154
+ * Otherwise, an error is thrown to indicate that the lock could not be acquired.
146
155
  */
147
- export async function doWithLock<T>(
156
+ export async function doWithLock<T, U = never>(
148
157
  name: string,
149
- options: LockOptions,
158
+ options: WithLockOptions<U>,
150
159
  func: () => Promise<T>,
151
- ): Promise<T> {
152
- const lock = await waitLockAsync(name, options);
160
+ ): Promise<T | U> {
161
+ const lock = await tryLockAsync(name, options);
162
+
163
+ if (!lock) {
164
+ if (options.onNotAcquired) {
165
+ return await options.onNotAcquired();
166
+ } else {
167
+ throw new Error(`failed to acquire lock: ${name}`);
168
+ }
169
+ }
170
+
153
171
  try {
154
172
  return await func();
155
173
  } finally {
@@ -159,21 +177,25 @@ export async function doWithLock<T>(
159
177
 
160
178
  /**
161
179
  * Tries to acquire the given lock, executes the provided function with the lock held,
162
- * and releases the lock once the function has executed. If the lock cannot be acquired,
163
- * the function is not executed and null is returned.
180
+ * and releases the lock once the function has executed.
181
+ *
182
+ * If the lock cannot be acquired, the function is not executed. If an `onNotAcquired`
183
+ * function was provided, this function is called and its return value is returned.
184
+ * Otherwise, `null` is returned.
164
185
  */
165
- export async function tryWithLock<T>(
186
+ export async function tryWithLock<T, U = null>(
166
187
  name: string,
167
- options: LockOptions,
188
+ options: WithLockOptions<U>,
168
189
  func: () => Promise<T>,
169
- ): Promise<T | null> {
170
- const lock = await tryLockAsync(name, options);
171
- if (lock == null) return null;
172
- try {
173
- return await func();
174
- } finally {
175
- await releaseLockAsync(lock);
176
- }
190
+ ): Promise<T | U> {
191
+ return await doWithLock<T, U>(
192
+ name,
193
+ {
194
+ onNotAcquired: () => null as U,
195
+ ...options,
196
+ },
197
+ func,
198
+ );
177
199
  }
178
200
 
179
201
  /**