@prairielearn/named-locks 1.3.3 → 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,23 @@
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
+
9
+ ## 1.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 297bbce5a: Allow `tryLockAsync` and `tryWithLock` to accept a timeout
14
+
15
+ ### Patch Changes
16
+
17
+ - 2b003b4d9: Upgrade all dependencies
18
+ - Updated dependencies [2b003b4d9]
19
+ - @prairielearn/postgres@1.7.2
20
+
3
21
  ## 1.3.3
4
22
 
5
23
  ### Patch Changes
package/README.md CHANGED
@@ -16,7 +16,7 @@ await init(
16
16
  },
17
17
  (err) => {
18
18
  throw err;
19
- }
19
+ },
20
20
  );
21
21
  ```
22
22
 
@@ -42,7 +42,7 @@ await doWithLock(
42
42
  },
43
43
  async () => {
44
44
  console.log('Doing some work');
45
- }
45
+ },
46
46
  );
47
47
  ```
48
48
 
package/dist/index.d.ts CHANGED
@@ -27,7 +27,9 @@ interface LockOptions {
27
27
  */
28
28
  autoRenew?: boolean;
29
29
  }
30
- type TryLockOptions = Omit<LockOptions, 'timeout'>;
30
+ interface WithLockOptions<T> extends LockOptions {
31
+ onNotAcquired?: () => Promise<T> | T;
32
+ }
31
33
  export declare const pool: PostgresPool;
32
34
  /**
33
35
  * Initializes a new {@link PostgresPool} that will be used to acquire named locks.
@@ -45,7 +47,7 @@ export declare function close(): Promise<void>;
45
47
  *
46
48
  * @param name The name of the lock to acquire.
47
49
  */
48
- export declare function tryLockAsync(name: string, options?: TryLockOptions): Promise<Lock | null>;
50
+ export declare function tryLockAsync(name: string, options?: LockOptions): Promise<Lock | null>;
49
51
  export declare const tryLock: (arg1: string, callback: (err: NodeJS.ErrnoException, result: Lock | null) => void) => void;
50
52
  /**
51
53
  * Wait until a lock can be successfully acquired.
@@ -65,12 +67,19 @@ export declare const releaseLock: (arg1: Lock, callback: (err: NodeJS.ErrnoExcep
65
67
  /**
66
68
  * Acquires the given lock, executes the provided function with the lock held,
67
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.
68
74
  */
69
- 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>;
70
76
  /**
71
77
  * Tries to acquire the given lock, executes the provided function with the lock held,
72
- * and releases the lock once the function has executed. If the lock cannot be acquired,
73
- * 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.
74
83
  */
75
- export declare function tryWithLock<T>(name: string, options: TryLockOptions, 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>;
76
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.3.3",
3
+ "version": "1.5.0",
4
4
  "main": "./dist/index.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,10 +13,10 @@
13
13
  },
14
14
  "devDependencies": {
15
15
  "@prairielearn/tsconfig": "^0.0.0",
16
- "@types/node": "^18.16.16",
17
- "typescript": "^5.1.3"
16
+ "@types/node": "^18.16.19",
17
+ "typescript": "^5.1.6"
18
18
  },
19
19
  "dependencies": {
20
- "@prairielearn/postgres": "^1.7.1"
20
+ "@prairielearn/postgres": "^1.7.2"
21
21
  }
22
22
  }
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,7 +31,9 @@ interface LockOptions {
30
31
  autoRenew?: boolean;
31
32
  }
32
33
 
33
- type TryLockOptions = Omit<LockOptions, 'timeout'>;
34
+ interface WithLockOptions<T> extends LockOptions {
35
+ onNotAcquired?: () => Promise<T> | T;
36
+ }
34
37
 
35
38
  /*
36
39
  * The functions here all identify locks by "name", which is a plain
@@ -84,13 +87,13 @@ let renewIntervalMs = 60_000;
84
87
  export async function init(
85
88
  pgConfig: PoolConfig,
86
89
  idleErrorHandler: (error: Error, client: PoolClient) => void,
87
- namedLocksConfig: NamedLocksConfig = {}
90
+ namedLocksConfig: NamedLocksConfig = {},
88
91
  ) {
89
92
  renewIntervalMs = namedLocksConfig.renewIntervalMs ?? renewIntervalMs;
90
93
  await pool.initAsync(pgConfig, idleErrorHandler);
91
94
  await pool.queryAsync(
92
95
  'CREATE TABLE IF NOT EXISTS named_locks (id bigserial PRIMARY KEY, name text NOT NULL UNIQUE);',
93
- {}
96
+ {},
94
97
  );
95
98
  }
96
99
 
@@ -109,10 +112,7 @@ export async function close() {
109
112
  *
110
113
  * @param name The name of the lock to acquire.
111
114
  */
112
- export async function tryLockAsync(
113
- name: string,
114
- options: TryLockOptions = {}
115
- ): Promise<Lock | null> {
115
+ export async function tryLockAsync(name: string, options: LockOptions = {}): Promise<Lock | null> {
116
116
  return getLock(name, { timeout: 0, ...options });
117
117
  }
118
118
 
@@ -148,13 +148,26 @@ export const releaseLock = util.callbackify(releaseLockAsync);
148
148
  /**
149
149
  * Acquires the given lock, executes the provided function with the lock held,
150
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.
151
155
  */
152
- export async function doWithLock<T>(
156
+ export async function doWithLock<T, U = never>(
153
157
  name: string,
154
- options: LockOptions,
155
- func: () => Promise<T>
156
- ): Promise<T> {
157
- const lock = await waitLockAsync(name, options);
158
+ options: WithLockOptions<U>,
159
+ func: () => Promise<T>,
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
+
158
171
  try {
159
172
  return await func();
160
173
  } finally {
@@ -164,21 +177,25 @@ export async function doWithLock<T>(
164
177
 
165
178
  /**
166
179
  * Tries to acquire the given lock, executes the provided function with the lock held,
167
- * and releases the lock once the function has executed. If the lock cannot be acquired,
168
- * 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.
169
185
  */
170
- export async function tryWithLock<T>(
186
+ export async function tryWithLock<T, U = null>(
171
187
  name: string,
172
- options: TryLockOptions,
173
- func: () => Promise<T>
174
- ): Promise<T | null> {
175
- const lock = await tryLockAsync(name, options);
176
- if (lock == null) return null;
177
- try {
178
- return await func();
179
- } finally {
180
- await releaseLockAsync(lock);
181
- }
188
+ options: WithLockOptions<U>,
189
+ func: () => Promise<T>,
190
+ ): Promise<T | U> {
191
+ return await doWithLock<T, U>(
192
+ name,
193
+ {
194
+ onNotAcquired: () => null as U,
195
+ ...options,
196
+ },
197
+ func,
198
+ );
182
199
  }
183
200
 
184
201
  /**
@@ -192,7 +209,7 @@ export async function tryWithLock<T>(
192
209
  async function getLock(name: string, options: LockOptions) {
193
210
  await pool.queryAsync(
194
211
  'INSERT INTO named_locks (name) VALUES ($name) ON CONFLICT (name) DO NOTHING;',
195
- { name }
212
+ { name },
196
213
  );
197
214
 
198
215
  const client = await pool.beginTransactionAsync();
@@ -206,7 +223,7 @@ async function getLock(name: string, options: LockOptions) {
206
223
  await pool.queryWithClientAsync(
207
224
  client,
208
225
  `SET LOCAL lock_timeout = ${client.escapeLiteral(options.timeout.toString())}`,
209
- {}
226
+ {},
210
227
  );
211
228
  }
212
229