velocious 1.0.699 → 1.0.700
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 +1 -2
- package/build/configuration-types.js +11 -0
- package/build/configuration.js +122 -1
- package/build/database/advisory-lock-backend-policy.js +204 -0
- package/build/database/advisory-lock-file-backend.js +348 -0
- package/build/database/advisory-lock-runner.js +239 -16
- package/build/environment-handlers/base.js +13 -0
- package/build/environment-handlers/node.js +11 -0
- package/build/http-server/server-lock.js +21 -115
- package/build/src/configuration-types.d.ts +31 -0
- package/build/src/configuration-types.d.ts.map +1 -1
- package/build/src/configuration-types.js +11 -1
- package/build/src/configuration.d.ts +88 -1
- package/build/src/configuration.d.ts.map +1 -1
- package/build/src/configuration.js +112 -2
- package/build/src/database/advisory-lock-backend-policy.d.ts +145 -0
- package/build/src/database/advisory-lock-backend-policy.d.ts.map +1 -0
- package/build/src/database/advisory-lock-backend-policy.js +184 -0
- package/build/src/database/advisory-lock-file-backend.d.ts +194 -0
- package/build/src/database/advisory-lock-file-backend.d.ts.map +1 -0
- package/build/src/database/advisory-lock-file-backend.js +313 -0
- package/build/src/database/advisory-lock-runner.d.ts +116 -15
- package/build/src/database/advisory-lock-runner.d.ts.map +1 -1
- package/build/src/database/advisory-lock-runner.js +190 -17
- package/build/src/environment-handlers/base.d.ts +14 -0
- package/build/src/environment-handlers/base.d.ts.map +1 -1
- package/build/src/environment-handlers/base.js +13 -1
- package/build/src/environment-handlers/node.d.ts +11 -0
- package/build/src/environment-handlers/node.d.ts.map +1 -1
- package/build/src/environment-handlers/node.js +11 -1
- package/build/src/http-server/server-lock.d.ts +13 -37
- package/build/src/http-server/server-lock.d.ts.map +1 -1
- package/build/src/http-server/server-lock.js +22 -109
- package/package.json +1 -1
- package/src/configuration-types.js +11 -0
- package/src/configuration.js +122 -1
- package/src/database/advisory-lock-backend-policy.js +204 -0
- package/src/database/advisory-lock-file-backend.js +348 -0
- package/src/database/advisory-lock-runner.js +239 -16
- package/src/environment-handlers/base.js +13 -0
- package/src/environment-handlers/node.js +11 -0
- package/src/http-server/server-lock.js +21 -115
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import wait from "awaitery/build/wait.js";
|
|
7
|
+
/**
|
|
8
|
+
* Owner metadata written inside one file-lock directory.
|
|
9
|
+
* @typedef {object} AdvisoryLockFileOwner
|
|
10
|
+
* @property {number} pid - PID of the holding process.
|
|
11
|
+
* @property {string} hostname - Host of the holding process.
|
|
12
|
+
* @property {string} holderId - Unique id of the acquiring backend instance.
|
|
13
|
+
* @property {string} acquiredAt - ISO timestamp of acquisition.
|
|
14
|
+
* @property {string} leaseExpiresAt - ISO timestamp when the current lease expires without renewal.
|
|
15
|
+
* @property {string} [host] - Extra owner field: HTTP host (server lock only).
|
|
16
|
+
* @property {number} [port] - Extra owner field: HTTP port (server lock only).
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Directory-based advisory-lock backend for the STC-210 `file` tier
|
|
20
|
+
* (`docs/advisory-lock-backends.md` tier (d)). This generalizes the pattern
|
|
21
|
+
* already used by `src/http-server/server-lock.js` and the Node SQLite
|
|
22
|
+
* driver's filesystem layer into one reusable backend behind the shared
|
|
23
|
+
* advisory-lock seam:
|
|
24
|
+
*
|
|
25
|
+
* - Atomic publication: a lock is claimed by `fs.mkdtemp` + `fs.rename` onto
|
|
26
|
+
* the stable lock path, so a losing candidate never observes or deletes a
|
|
27
|
+
* half-written owner record.
|
|
28
|
+
* - Lease + renewal: each hold carries a `leaseMs` lease renewed on
|
|
29
|
+
* `renewIntervalMs` while held, so a holder that dies without releasing
|
|
30
|
+
* (or whose PID was recycled) is reclaimable once the lease expires.
|
|
31
|
+
* - Staleness: a lock directory is stale when its owner metadata is
|
|
32
|
+
* unreadable, its lease expired, or its owner is a dead local process
|
|
33
|
+
* (`kill(pid, 0)` → `ESRCH`). Cross-host owners are only reclaimable via
|
|
34
|
+
* lease expiry because PID liveness cannot be probed remotely.
|
|
35
|
+
*
|
|
36
|
+
* This tier provides no fencing tokens (design §8: a file lock has no
|
|
37
|
+
* monotonic authority a partitioned holder can be checked against), so
|
|
38
|
+
* acquisitions report `fencingSupported: false` instead of pretending.
|
|
39
|
+
*/
|
|
40
|
+
export default class AdvisoryLockFileBackend {
|
|
41
|
+
/**
|
|
42
|
+
* Creates one file-lock backend.
|
|
43
|
+
* @param {object} args - Backend options.
|
|
44
|
+
* @param {string} args.directory - Directory that holds the lock directories.
|
|
45
|
+
* @param {Record<string, string | number>} [args.extraOwnerFields] - Extra fields merged into every owner metadata record (e.g. the HTTP server lock's host/port).
|
|
46
|
+
* @param {number} [args.leaseMs] - Lease duration for one hold; expired leases make a lock stale. Defaults to 30000.
|
|
47
|
+
* @param {number} [args.renewIntervalMs] - Renewal cadence while holding; must stay below `leaseMs`. Defaults to 10000.
|
|
48
|
+
* @param {"hashed" | "plain"} [args.pathStyle] - `hashed` derives `<safeName>-<hash>.lock` names (advisory-lock tier); `plain` uses `<name>.lock` (HTTP server lock). Defaults to `hashed`.
|
|
49
|
+
* @param {number} [args.pollIntervalMs] - Wait between acquisition retries. Defaults to 50.
|
|
50
|
+
*/
|
|
51
|
+
constructor({ directory, extraOwnerFields = {}, leaseMs = 30_000, renewIntervalMs = 10_000, pathStyle = "hashed", pollIntervalMs = 50 }) {
|
|
52
|
+
this.directory = directory;
|
|
53
|
+
this.extraOwnerFields = extraOwnerFields;
|
|
54
|
+
this.leaseMs = leaseMs;
|
|
55
|
+
this.renewIntervalMs = renewIntervalMs;
|
|
56
|
+
this.pathStyle = pathStyle;
|
|
57
|
+
this.pollIntervalMs = pollIntervalMs;
|
|
58
|
+
this.holderId = `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
59
|
+
/** @type {Map<string, {timer: ReturnType<typeof setInterval>}>} */
|
|
60
|
+
this.holdsByName = new Map();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolves the stable lock directory path for one lock name.
|
|
64
|
+
* @param {string} name - Lock name.
|
|
65
|
+
* @returns {string} - Filesystem path for the lock directory.
|
|
66
|
+
*/
|
|
67
|
+
lockPathFor(name) {
|
|
68
|
+
if (this.pathStyle === "plain")
|
|
69
|
+
return path.join(this.directory, `${name}.lock`);
|
|
70
|
+
const hash = createHash("sha256").update(name).digest("hex").slice(0, 16);
|
|
71
|
+
const safeName = name.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 64);
|
|
72
|
+
return path.join(this.directory, `${safeName}-${hash}.lock`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Blocks until the named lock is acquired or `timeoutMs` elapses.
|
|
76
|
+
* @param {string} name - Lock name.
|
|
77
|
+
* @param {{timeoutMs?: number | null}} [args] - Timeout args; `null`, `undefined`, or negative waits indefinitely.
|
|
78
|
+
* @returns {Promise<boolean>} - True when acquired, false when the timeout elapsed.
|
|
79
|
+
*/
|
|
80
|
+
async acquire(name, { timeoutMs } = {}) {
|
|
81
|
+
const deadline = typeof timeoutMs === "number" && timeoutMs >= 0 ? Date.now() + timeoutMs : null;
|
|
82
|
+
await this.ensureDirectory();
|
|
83
|
+
// Intentionally looping without a fixed iteration cap — either the
|
|
84
|
+
// publication succeeds, the deadline elapses, or an unexpected error is
|
|
85
|
+
// re-thrown.
|
|
86
|
+
while (true) {
|
|
87
|
+
if (await this.tryAcquire(name))
|
|
88
|
+
return true;
|
|
89
|
+
if (deadline !== null) {
|
|
90
|
+
const remaining = deadline - Date.now();
|
|
91
|
+
if (remaining <= 0)
|
|
92
|
+
return false;
|
|
93
|
+
await wait(Math.min(this.pollIntervalMs, remaining));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
await wait(this.pollIntervalMs);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Attempts to acquire the named lock without waiting, reclaiming a stale
|
|
102
|
+
* lock directory when one is found.
|
|
103
|
+
* @param {string} name - Lock name.
|
|
104
|
+
* @returns {Promise<boolean>} - True when this backend became the lock owner.
|
|
105
|
+
*/
|
|
106
|
+
async tryAcquire(name) {
|
|
107
|
+
if (this.holdsByName.has(name))
|
|
108
|
+
return false;
|
|
109
|
+
await this.ensureDirectory();
|
|
110
|
+
const lockPath = this.lockPathFor(name);
|
|
111
|
+
if (await this.publishLockDirectory(lockPath))
|
|
112
|
+
return this.startHold(name);
|
|
113
|
+
if (await this.isStale(lockPath)) {
|
|
114
|
+
await fs.rm(lockPath, { recursive: true, force: true });
|
|
115
|
+
if (await this.publishLockDirectory(lockPath))
|
|
116
|
+
return this.startHold(name);
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Releases the lock only when this backend instance owns it, mirroring the
|
|
122
|
+
* "you can only release locks you own" contract of the database tiers.
|
|
123
|
+
* @param {string} name - Lock name.
|
|
124
|
+
* @returns {Promise<boolean>} - True when the held lock was released.
|
|
125
|
+
*/
|
|
126
|
+
async release(name) {
|
|
127
|
+
const hold = this.holdsByName.get(name);
|
|
128
|
+
if (!hold)
|
|
129
|
+
return false;
|
|
130
|
+
this.clearHold(name);
|
|
131
|
+
const owner = await this.readOwner(this.lockPathFor(name));
|
|
132
|
+
if (!owner || owner.holderId !== this.holderId)
|
|
133
|
+
return false;
|
|
134
|
+
await fs.rm(this.lockPathFor(name), { recursive: true, force: true });
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Runs is held.
|
|
139
|
+
* @param {string} name - Lock name.
|
|
140
|
+
* @returns {Promise<boolean>} - Whether the lock is currently held by a live, unexpired owner.
|
|
141
|
+
*/
|
|
142
|
+
async isHeld(name) {
|
|
143
|
+
const lockPath = this.lockPathFor(name);
|
|
144
|
+
try {
|
|
145
|
+
await fs.stat(lockPath);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return !await this.isStale(lockPath);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Reads the current owner metadata for diagnostics.
|
|
154
|
+
* @param {string} name - Lock name.
|
|
155
|
+
* @returns {Promise<AdvisoryLockFileOwner | null>} - Parsed owner metadata, when a lock directory exists.
|
|
156
|
+
*/
|
|
157
|
+
async holderInfo(name) {
|
|
158
|
+
return await this.readOwner(this.lockPathFor(name));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Releases every lock this backend instance currently holds (shutdown path).
|
|
162
|
+
* @returns {Promise<void>} - Resolves after best-effort release of all holds.
|
|
163
|
+
*/
|
|
164
|
+
async releaseAllHeld() {
|
|
165
|
+
for (const name of [...this.holdsByName.keys()]) {
|
|
166
|
+
await this.release(name);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Ensures the parent lock directory exists.
|
|
171
|
+
* @returns {Promise<void>} - Resolves after the directory exists.
|
|
172
|
+
*/
|
|
173
|
+
async ensureDirectory() {
|
|
174
|
+
await fs.mkdir(this.directory, { recursive: true });
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Publishes a fully initialized lock directory with one atomic rename so
|
|
178
|
+
* concurrent candidates cannot observe a half-written owner record.
|
|
179
|
+
* @param {string} lockPath - Stable lock directory path.
|
|
180
|
+
* @returns {Promise<boolean>} - Whether this candidate became the lock owner.
|
|
181
|
+
*/
|
|
182
|
+
async publishLockDirectory(lockPath) {
|
|
183
|
+
const candidatePath = await fs.mkdtemp(`${lockPath}.pending-`);
|
|
184
|
+
let published = false;
|
|
185
|
+
try {
|
|
186
|
+
await this.writeOwner(candidatePath);
|
|
187
|
+
try {
|
|
188
|
+
await fs.rename(candidatePath, lockPath);
|
|
189
|
+
published = true;
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
const code = /** @type {Error & {code?: string}} */ (error)?.code;
|
|
194
|
+
if (code === "EEXIST" || code === "ENOTEMPTY")
|
|
195
|
+
return false;
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
if (!published)
|
|
201
|
+
await fs.rm(candidatePath, { recursive: true, force: true });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Starts lease renewal for a freshly acquired hold.
|
|
206
|
+
* @param {string} name - Lock name.
|
|
207
|
+
* @returns {true} - Always true; the hold is now tracked.
|
|
208
|
+
*/
|
|
209
|
+
startHold(name) {
|
|
210
|
+
const timer = setInterval(() => {
|
|
211
|
+
void this.renewHold(name);
|
|
212
|
+
}, this.renewIntervalMs);
|
|
213
|
+
if (typeof timer.unref === "function")
|
|
214
|
+
timer.unref();
|
|
215
|
+
this.holdsByName.set(name, { timer });
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Extends this instance's lease on one held lock; stops renewing when the
|
|
220
|
+
* directory is no longer ours (the lock was reclaimed).
|
|
221
|
+
* @param {string} name - Lock name.
|
|
222
|
+
* @returns {Promise<void>} - Resolves after the renewal attempt.
|
|
223
|
+
*/
|
|
224
|
+
async renewHold(name) {
|
|
225
|
+
const hold = this.holdsByName.get(name);
|
|
226
|
+
if (!hold)
|
|
227
|
+
return;
|
|
228
|
+
const owner = await this.readOwner(this.lockPathFor(name));
|
|
229
|
+
if (!owner || owner.holderId !== this.holderId) {
|
|
230
|
+
this.clearHold(name);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
await this.writeOwner(this.lockPathFor(name));
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Clears the renewal timer for one hold.
|
|
237
|
+
* @param {string} name - Lock name.
|
|
238
|
+
* @returns {void}
|
|
239
|
+
*/
|
|
240
|
+
clearHold(name) {
|
|
241
|
+
const hold = this.holdsByName.get(name);
|
|
242
|
+
if (!hold)
|
|
243
|
+
return;
|
|
244
|
+
clearInterval(hold.timer);
|
|
245
|
+
this.holdsByName.delete(name);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Writes owner + lease metadata into a lock directory.
|
|
249
|
+
* @param {string} lockDirPath - Lock directory to write metadata into.
|
|
250
|
+
* @returns {Promise<void>} - Resolves after metadata is written.
|
|
251
|
+
*/
|
|
252
|
+
async writeOwner(lockDirPath) {
|
|
253
|
+
/** @type {AdvisoryLockFileOwner} */
|
|
254
|
+
const owner = {
|
|
255
|
+
acquiredAt: new Date().toISOString(),
|
|
256
|
+
holderId: this.holderId,
|
|
257
|
+
hostname: os.hostname(),
|
|
258
|
+
leaseExpiresAt: new Date(Date.now() + this.leaseMs).toISOString(),
|
|
259
|
+
pid: process.pid,
|
|
260
|
+
...this.extraOwnerFields
|
|
261
|
+
};
|
|
262
|
+
await fs.writeFile(path.join(lockDirPath, "owner.json"), JSON.stringify(owner));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Reads owner metadata from a lock directory.
|
|
266
|
+
* @param {string} lockPath - Lock directory path.
|
|
267
|
+
* @returns {Promise<AdvisoryLockFileOwner | null>} - Parsed owner metadata, when readable.
|
|
268
|
+
*/
|
|
269
|
+
async readOwner(lockPath) {
|
|
270
|
+
/** @type {string} */
|
|
271
|
+
let rawOwner;
|
|
272
|
+
try {
|
|
273
|
+
rawOwner = await fs.readFile(path.join(lockPath, "owner.json"), "utf8");
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
return /** @type {AdvisoryLockFileOwner} */ (JSON.parse(rawOwner));
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* A lock directory is stale when its metadata is unreadable, its lease has
|
|
287
|
+
* expired, or its owner is a dead process on this host. Cross-host owners
|
|
288
|
+
* are only reclaimable via lease expiry — PID probing is unreliable beyond
|
|
289
|
+
* one host, which is exactly why this tier is the opt-in single-host last
|
|
290
|
+
* resort (design §4/§8).
|
|
291
|
+
* @param {string} lockPath - Lock directory path.
|
|
292
|
+
* @returns {Promise<boolean>} - Whether the lock can be reclaimed.
|
|
293
|
+
*/
|
|
294
|
+
async isStale(lockPath) {
|
|
295
|
+
const owner = await this.readOwner(lockPath);
|
|
296
|
+
if (!owner || typeof owner.pid !== "number")
|
|
297
|
+
return true;
|
|
298
|
+
if (owner.leaseExpiresAt && new Date(owner.leaseExpiresAt).getTime() <= Date.now())
|
|
299
|
+
return true;
|
|
300
|
+
if (owner.hostname && owner.hostname !== os.hostname())
|
|
301
|
+
return false;
|
|
302
|
+
try {
|
|
303
|
+
// `kill(pid, 0)` is a no-op signal that fails with ESRCH when the
|
|
304
|
+
// process is gone; permission errors still prove the process exists.
|
|
305
|
+
process.kill(owner.pid, 0);
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
return /** @type {Error & {code?: string}} */ (error).code === "ESRCH";
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWR2aXNvcnktbG9jay1maWxlLWJhY2tlbmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZGF0YWJhc2UvYWR2aXNvcnktbG9jay1maWxlLWJhY2tlbmQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSxhQUFhLENBQUE7QUFDdEMsT0FBTyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDakMsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQ3hCLE9BQU8sSUFBSSxNQUFNLFdBQVcsQ0FBQTtBQUM1QixPQUFPLElBQUksTUFBTSx3QkFBd0IsQ0FBQTtBQUV6Qzs7Ozs7Ozs7OztHQVVHO0FBRUg7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sdUJBQXVCO0lBQzFDOzs7Ozs7Ozs7T0FTRztJQUNILFlBQVksRUFBQyxTQUFTLEVBQUUsZ0JBQWdCLEdBQUcsRUFBRSxFQUFFLE9BQU8sR0FBRyxNQUFNLEVBQUUsZUFBZSxHQUFHLE1BQU0sRUFBRSxTQUFTLEdBQUcsUUFBUSxFQUFFLGNBQWMsR0FBRyxFQUFFLEVBQUM7UUFDbkksSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUE7UUFDMUIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLGdCQUFnQixDQUFBO1FBQ3hDLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFBO1FBQ3RCLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFBO1FBQ3RDLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFBO1FBQzFCLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFBO1FBQ3BDLElBQUksQ0FBQyxRQUFRLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUs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QUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQge2NyZWF0ZUhhc2h9IGZyb20gXCJub2RlOmNyeXB0b1wiXG5pbXBvcnQgZnMgZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIlxuaW1wb3J0IG9zIGZyb20gXCJub2RlOm9zXCJcbmltcG9ydCBwYXRoIGZyb20gXCJub2RlOnBhdGhcIlxuaW1wb3J0IHdhaXQgZnJvbSBcImF3YWl0ZXJ5L2J1aWxkL3dhaXQuanNcIlxuXG4vKipcbiAqIE93bmVyIG1ldGFkYXRhIHdyaXR0ZW4gaW5zaWRlIG9uZSBmaWxlLWxvY2sgZGlyZWN0b3J5LlxuICogQHR5cGVkZWYge29iamVjdH0gQWR2aXNvcnlMb2NrRmlsZU93bmVyXG4gKiBAcHJvcGVydHkge251bWJlcn0gcGlkIC0gUElEIG9mIHRoZSBob2xkaW5nIHByb2Nlc3MuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaG9zdG5hbWUgLSBIb3N0IG9mIHRoZSBob2xkaW5nIHByb2Nlc3MuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaG9sZGVySWQgLSBVbmlxdWUgaWQgb2YgdGhlIGFjcXVpcmluZyBiYWNrZW5kIGluc3RhbmNlLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGFjcXVpcmVkQXQgLSBJU08gdGltZXN0YW1wIG9mIGFjcXVpc2l0aW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGxlYXNlRXhwaXJlc0F0IC0gSVNPIHRpbWVzdGFtcCB3aGVuIHRoZSBjdXJyZW50IGxlYXNlIGV4cGlyZXMgd2l0aG91dCByZW5ld2FsLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtob3N0XSAtIEV4dHJhIG93bmVyIGZpZWxkOiBIVFRQIGhvc3QgKHNlcnZlciBsb2NrIG9ubHkpLlxuICogQHByb3BlcnR5IHtudW1iZXJ9IFtwb3J0XSAtIEV4dHJhIG93bmVyIGZpZWxkOiBIVFRQIHBvcnQgKHNlcnZlciBsb2NrIG9ubHkpLlxuICovXG5cbi8qKlxuICogRGlyZWN0b3J5LWJhc2VkIGFkdmlzb3J5LWxvY2sgYmFja2VuZCBmb3IgdGhlIFNUQy0yMTAgYGZpbGVgIHRpZXJcbiAqIChgZG9jcy9hZHZpc29yeS1sb2NrLWJhY2tlbmRzLm1kYCB0aWVyIChkKSkuIFRoaXMgZ2VuZXJhbGl6ZXMgdGhlIHBhdHRlcm5cbiAqIGFscmVhZHkgdXNlZCBieSBgc3JjL2h0dHAtc2VydmVyL3NlcnZlci1sb2NrLmpzYCBhbmQgdGhlIE5vZGUgU1FMaXRlXG4gKiBkcml2ZXIncyBmaWxlc3lzdGVtIGxheWVyIGludG8gb25lIHJldXNhYmxlIGJhY2tlbmQgYmVoaW5kIHRoZSBzaGFyZWRcbiAqIGFkdmlzb3J5LWxvY2sgc2VhbTpcbiAqXG4gKiAtIEF0b21pYyBwdWJsaWNhdGlvbjogYSBsb2NrIGlzIGNsYWltZWQgYnkgYGZzLm1rZHRlbXBgICsgYGZzLnJlbmFtZWAgb250b1xuICogICB0aGUgc3RhYmxlIGxvY2sgcGF0aCwgc28gYSBsb3NpbmcgY2FuZGlkYXRlIG5ldmVyIG9ic2VydmVzIG9yIGRlbGV0ZXMgYVxuICogICBoYWxmLXdyaXR0ZW4gb3duZXIgcmVjb3JkLlxuICogLSBMZWFzZSArIHJlbmV3YWw6IGVhY2ggaG9sZCBjYXJyaWVzIGEgYGxlYXNlTXNgIGxlYXNlIHJlbmV3ZWQgb25cbiAqICAgYHJlbmV3SW50ZXJ2YWxNc2Agd2hpbGUgaGVsZCwgc28gYSBob2xkZXIgdGhhdCBkaWVzIHdpdGhvdXQgcmVsZWFzaW5nXG4gKiAgIChvciB3aG9zZSBQSUQgd2FzIHJlY3ljbGVkKSBpcyByZWNsYWltYWJsZSBvbmNlIHRoZSBsZWFzZSBleHBpcmVzLlxuICogLSBTdGFsZW5lc3M6IGEgbG9jayBkaXJlY3RvcnkgaXMgc3RhbGUgd2hlbiBpdHMgb3duZXIgbWV0YWRhdGEgaXNcbiAqICAgdW5yZWFkYWJsZSwgaXRzIGxlYXNlIGV4cGlyZWQsIG9yIGl0cyBvd25lciBpcyBhIGRlYWQgbG9jYWwgcHJvY2Vzc1xuICogICAoYGtpbGwocGlkLCAwKWAg4oaSIGBFU1JDSGApLiBDcm9zcy1ob3N0IG93bmVycyBhcmUgb25seSByZWNsYWltYWJsZSB2aWFcbiAqICAgbGVhc2UgZXhwaXJ5IGJlY2F1c2UgUElEIGxpdmVuZXNzIGNhbm5vdCBiZSBwcm9iZWQgcmVtb3RlbHkuXG4gKlxuICogVGhpcyB0aWVyIHByb3ZpZGVzIG5vIGZlbmNpbmcgdG9rZW5zIChkZXNpZ24gwqc4OiBhIGZpbGUgbG9jayBoYXMgbm9cbiAqIG1vbm90b25pYyBhdXRob3JpdHkgYSBwYXJ0aXRpb25lZCBob2xkZXIgY2FuIGJlIGNoZWNrZWQgYWdhaW5zdCksIHNvXG4gKiBhY3F1aXNpdGlvbnMgcmVwb3J0IGBmZW5jaW5nU3VwcG9ydGVkOiBmYWxzZWAgaW5zdGVhZCBvZiBwcmV0ZW5kaW5nLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBBZHZpc29yeUxvY2tGaWxlQmFja2VuZCB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIG9uZSBmaWxlLWxvY2sgYmFja2VuZC5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBCYWNrZW5kIG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmRpcmVjdG9yeSAtIERpcmVjdG9yeSB0aGF0IGhvbGRzIHRoZSBsb2NrIGRpcmVjdG9yaWVzLlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlcj59IFthcmdzLmV4dHJhT3duZXJGaWVsZHNdIC0gRXh0cmEgZmllbGRzIG1lcmdlZCBpbnRvIGV2ZXJ5IG93bmVyIG1ldGFkYXRhIHJlY29yZCAoZS5nLiB0aGUgSFRUUCBzZXJ2ZXIgbG9jaydzIGhvc3QvcG9ydCkuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5sZWFzZU1zXSAtIExlYXNlIGR1cmF0aW9uIGZvciBvbmUgaG9sZDsgZXhwaXJlZCBsZWFzZXMgbWFrZSBhIGxvY2sgc3RhbGUuIERlZmF1bHRzIHRvIDMwMDAwLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MucmVuZXdJbnRlcnZhbE1zXSAtIFJlbmV3YWwgY2FkZW5jZSB3aGlsZSBob2xkaW5nOyBtdXN0IHN0YXkgYmVsb3cgYGxlYXNlTXNgLiBEZWZhdWx0cyB0byAxMDAwMC5cbiAgICogQHBhcmFtIHtcImhhc2hlZFwiIHwgXCJwbGFpblwifSBbYXJncy5wYXRoU3R5bGVdIC0gYGhhc2hlZGAgZGVyaXZlcyBgPHNhZmVOYW1lPi08aGFzaD4ubG9ja2AgbmFtZXMgKGFkdmlzb3J5LWxvY2sgdGllcik7IGBwbGFpbmAgdXNlcyBgPG5hbWU+LmxvY2tgIChIVFRQIHNlcnZlciBsb2NrKS4gRGVmYXVsdHMgdG8gYGhhc2hlZGAuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5wb2xsSW50ZXJ2YWxNc10gLSBXYWl0IGJldHdlZW4gYWNxdWlzaXRpb24gcmV0cmllcy4gRGVmYXVsdHMgdG8gNTAuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7ZGlyZWN0b3J5LCBleHRyYU93bmVyRmllbGRzID0ge30sIGxlYXNlTXMgPSAzMF8wMDAsIHJlbmV3SW50ZXJ2YWxNcyA9IDEwXzAwMCwgcGF0aFN0eWxlID0gXCJoYXNoZWRcIiwgcG9sbEludGVydmFsTXMgPSA1MH0pIHtcbiAgICB0aGlzLmRpcmVjdG9yeSA9IGRpcmVjdG9yeVxuICAgIHRoaXMuZXh0cmFPd25lckZpZWxkcyA9IGV4dHJhT3duZXJGaWVsZHNcbiAgICB0aGlzLmxlYXNlTXMgPSBsZWFzZU1zXG4gICAgdGhpcy5yZW5ld0ludGVydmFsTXMgPSByZW5ld0ludGVydmFsTXNcbiAgICB0aGlzLnBhdGhTdHlsZSA9IHBhdGhTdHlsZVxuICAgIHRoaXMucG9sbEludGVydmFsTXMgPSBwb2xsSW50ZXJ2YWxNc1xuICAgIHRoaXMuaG9sZGVySWQgPSBgJHtwcm9jZXNzLnBpZH0tJHtEYXRlLm5vdygpfS0ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIsIDEwKX1gXG4gICAgLyoqIEB0eXBlIHtNYXA8c3RyaW5nLCB7dGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPn0+fSAqL1xuICAgIHRoaXMuaG9sZHNCeU5hbWUgPSBuZXcgTWFwKClcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgc3RhYmxlIGxvY2sgZGlyZWN0b3J5IHBhdGggZm9yIG9uZSBsb2NrIG5hbWUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIEZpbGVzeXN0ZW0gcGF0aCBmb3IgdGhlIGxvY2sgZGlyZWN0b3J5LlxuICAgKi9cbiAgbG9ja1BhdGhGb3IobmFtZSkge1xuICAgIGlmICh0aGlzLnBhdGhTdHlsZSA9PT0gXCJwbGFpblwiKSByZXR1cm4gcGF0aC5qb2luKHRoaXMuZGlyZWN0b3J5LCBgJHtuYW1lfS5sb2NrYClcblxuICAgIGNvbnN0IGhhc2ggPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShuYW1lKS5kaWdlc3QoXCJoZXhcIikuc2xpY2UoMCwgMTYpXG4gICAgY29uc3Qgc2FmZU5hbWUgPSBuYW1lLnJlcGxhY2UoL1teYS16QS1aMC05Ll8tXS9nLCBcIl9cIikuc2xpY2UoMCwgNjQpXG5cbiAgICByZXR1cm4gcGF0aC5qb2luKHRoaXMuZGlyZWN0b3J5LCBgJHtzYWZlTmFtZX0tJHtoYXNofS5sb2NrYClcbiAgfVxuXG4gIC8qKlxuICAgKiBCbG9ja3MgdW50aWwgdGhlIG5hbWVkIGxvY2sgaXMgYWNxdWlyZWQgb3IgYHRpbWVvdXRNc2AgZWxhcHNlcy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBMb2NrIG5hbWUuXG4gICAqIEBwYXJhbSB7e3RpbWVvdXRNcz86IG51bWJlciB8IG51bGx9fSBbYXJnc10gLSBUaW1lb3V0IGFyZ3M7IGBudWxsYCwgYHVuZGVmaW5lZGAsIG9yIG5lZ2F0aXZlIHdhaXRzIGluZGVmaW5pdGVseS5cbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IC0gVHJ1ZSB3aGVuIGFjcXVpcmVkLCBmYWxzZSB3aGVuIHRoZSB0aW1lb3V0IGVsYXBzZWQuXG4gICAqL1xuICBhc3luYyBhY3F1aXJlKG5hbWUsIHt0aW1lb3V0TXN9ID0ge30pIHtcbiAgICBjb25zdCBkZWFkbGluZSA9IHR5cGVvZiB0aW1lb3V0TXMgPT09IFwibnVtYmVyXCIgJiYgdGltZW91dE1zID49IDAgPyBEYXRlLm5vdygpICsgdGltZW91dE1zIDogbnVsbFxuXG4gICAgYXdhaXQgdGhpcy5lbnN1cmVEaXJlY3RvcnkoKVxuXG4gICAgLy8gSW50ZW50aW9uYWxseSBsb29waW5nIHdpdGhvdXQgYSBmaXhlZCBpdGVyYXRpb24gY2FwIOKAlCBlaXRoZXIgdGhlXG4gICAgLy8gcHVibGljYXRpb24gc3VjY2VlZHMsIHRoZSBkZWFkbGluZSBlbGFwc2VzLCBvciBhbiB1bmV4cGVjdGVkIGVycm9yIGlzXG4gICAgLy8gcmUtdGhyb3duLlxuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICBpZiAoYXdhaXQgdGhpcy50cnlBY3F1aXJlKG5hbWUpKSByZXR1cm4gdHJ1ZVxuXG4gICAgICBpZiAoZGVhZGxpbmUgIT09IG51bGwpIHtcbiAgICAgICAgY29uc3QgcmVtYWluaW5nID0gZGVhZGxpbmUgLSBEYXRlLm5vdygpXG5cbiAgICAgICAgaWYgKHJlbWFpbmluZyA8PSAwKSByZXR1cm4gZmFsc2VcblxuICAgICAgICBhd2FpdCB3YWl0KE1hdGgubWluKHRoaXMucG9sbEludGVydmFsTXMsIHJlbWFpbmluZykpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhd2FpdCB3YWl0KHRoaXMucG9sbEludGVydmFsTXMpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEF0dGVtcHRzIHRvIGFjcXVpcmUgdGhlIG5hbWVkIGxvY2sgd2l0aG91dCB3YWl0aW5nLCByZWNsYWltaW5nIGEgc3RhbGVcbiAgICogbG9jayBkaXJlY3Rvcnkgd2hlbiBvbmUgaXMgZm91bmQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gLSBUcnVlIHdoZW4gdGhpcyBiYWNrZW5kIGJlY2FtZSB0aGUgbG9jayBvd25lci5cbiAgICovXG4gIGFzeW5jIHRyeUFjcXVpcmUobmFtZSkge1xuICAgIGlmICh0aGlzLmhvbGRzQnlOYW1lLmhhcyhuYW1lKSkgcmV0dXJuIGZhbHNlXG5cbiAgICBhd2FpdCB0aGlzLmVuc3VyZURpcmVjdG9yeSgpXG5cbiAgICBjb25zdCBsb2NrUGF0aCA9IHRoaXMubG9ja1BhdGhGb3IobmFtZSlcblxuICAgIGlmIChhd2FpdCB0aGlzLnB1Ymxpc2hMb2NrRGlyZWN0b3J5KGxvY2tQYXRoKSkgcmV0dXJuIHRoaXMuc3RhcnRIb2xkKG5hbWUpXG5cbiAgICBpZiAoYXdhaXQgdGhpcy5pc1N0YWxlKGxvY2tQYXRoKSkge1xuICAgICAgYXdhaXQgZnMucm0obG9ja1BhdGgsIHtyZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlfSlcblxuICAgICAgaWYgKGF3YWl0IHRoaXMucHVibGlzaExvY2tEaXJlY3RvcnkobG9ja1BhdGgpKSByZXR1cm4gdGhpcy5zdGFydEhvbGQobmFtZSlcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWxlYXNlcyB0aGUgbG9jayBvbmx5IHdoZW4gdGhpcyBiYWNrZW5kIGluc3RhbmNlIG93bnMgaXQsIG1pcnJvcmluZyB0aGVcbiAgICogXCJ5b3UgY2FuIG9ubHkgcmVsZWFzZSBsb2NrcyB5b3Ugb3duXCIgY29udHJhY3Qgb2YgdGhlIGRhdGFiYXNlIHRpZXJzLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIExvY2sgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IC0gVHJ1ZSB3aGVuIHRoZSBoZWxkIGxvY2sgd2FzIHJlbGVhc2VkLlxuICAgKi9cbiAgYXN5bmMgcmVsZWFzZShuYW1lKSB7XG4gICAgY29uc3QgaG9sZCA9IHRoaXMuaG9sZHNCeU5hbWUuZ2V0KG5hbWUpXG5cbiAgICBpZiAoIWhvbGQpIHJldHVybiBmYWxzZVxuXG4gICAgdGhpcy5jbGVhckhvbGQobmFtZSlcblxuICAgIGNvbnN0IG93bmVyID0gYXdhaXQgdGhpcy5yZWFkT3duZXIodGhpcy5sb2NrUGF0aEZvcihuYW1lKSlcblxuICAgIGlmICghb3duZXIgfHwgb3duZXIuaG9sZGVySWQgIT09IHRoaXMuaG9sZGVySWQpIHJldHVybiBmYWxzZVxuXG4gICAgYXdhaXQgZnMucm0odGhpcy5sb2NrUGF0aEZvcihuYW1lKSwge3JlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWV9KVxuXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGlzIGhlbGQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gLSBXaGV0aGVyIHRoZSBsb2NrIGlzIGN1cnJlbnRseSBoZWxkIGJ5IGEgbGl2ZSwgdW5leHBpcmVkIG93bmVyLlxuICAgKi9cbiAgYXN5bmMgaXNIZWxkKG5hbWUpIHtcbiAgICBjb25zdCBsb2NrUGF0aCA9IHRoaXMubG9ja1BhdGhGb3IobmFtZSlcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmcy5zdGF0KGxvY2tQYXRoKVxuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuXG4gICAgcmV0dXJuICFhd2FpdCB0aGlzLmlzU3RhbGUobG9ja1BhdGgpXG4gIH1cblxuICAvKipcbiAgICogUmVhZHMgdGhlIGN1cnJlbnQgb3duZXIgbWV0YWRhdGEgZm9yIGRpYWdub3N0aWNzLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIExvY2sgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8QWR2aXNvcnlMb2NrRmlsZU93bmVyIHwgbnVsbD59IC0gUGFyc2VkIG93bmVyIG1ldGFkYXRhLCB3aGVuIGEgbG9jayBkaXJlY3RvcnkgZXhpc3RzLlxuICAgKi9cbiAgYXN5bmMgaG9sZGVySW5mbyhuYW1lKSB7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMucmVhZE93bmVyKHRoaXMubG9ja1BhdGhGb3IobmFtZSkpXG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZXMgZXZlcnkgbG9jayB0aGlzIGJhY2tlbmQgaW5zdGFuY2UgY3VycmVudGx5IGhvbGRzIChzaHV0ZG93biBwYXRoKS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgYmVzdC1lZmZvcnQgcmVsZWFzZSBvZiBhbGwgaG9sZHMuXG4gICAqL1xuICBhc3luYyByZWxlYXNlQWxsSGVsZCgpIHtcbiAgICBmb3IgKGNvbnN0IG5hbWUgb2YgWy4uLnRoaXMuaG9sZHNCeU5hbWUua2V5cygpXSkge1xuICAgICAgYXdhaXQgdGhpcy5yZWxlYXNlKG5hbWUpXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZXMgdGhlIHBhcmVudCBsb2NrIGRpcmVjdG9yeSBleGlzdHMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIHRoZSBkaXJlY3RvcnkgZXhpc3RzLlxuICAgKi9cbiAgYXN5bmMgZW5zdXJlRGlyZWN0b3J5KCkge1xuICAgIGF3YWl0IGZzLm1rZGlyKHRoaXMuZGlyZWN0b3J5LCB7cmVjdXJzaXZlOiB0cnVlfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWJsaXNoZXMgYSBmdWxseSBpbml0aWFsaXplZCBsb2NrIGRpcmVjdG9yeSB3aXRoIG9uZSBhdG9taWMgcmVuYW1lIHNvXG4gICAqIGNvbmN1cnJlbnQgY2FuZGlkYXRlcyBjYW5ub3Qgb2JzZXJ2ZSBhIGhhbGYtd3JpdHRlbiBvd25lciByZWNvcmQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBsb2NrUGF0aCAtIFN0YWJsZSBsb2NrIGRpcmVjdG9yeSBwYXRoLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gLSBXaGV0aGVyIHRoaXMgY2FuZGlkYXRlIGJlY2FtZSB0aGUgbG9jayBvd25lci5cbiAgICovXG4gIGFzeW5jIHB1Ymxpc2hMb2NrRGlyZWN0b3J5KGxvY2tQYXRoKSB7XG4gICAgY29uc3QgY2FuZGlkYXRlUGF0aCA9IGF3YWl0IGZzLm1rZHRlbXAoYCR7bG9ja1BhdGh9LnBlbmRpbmctYClcbiAgICBsZXQgcHVibGlzaGVkID0gZmFsc2VcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLndyaXRlT3duZXIoY2FuZGlkYXRlUGF0aClcblxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZnMucmVuYW1lKGNhbmRpZGF0ZVBhdGgsIGxvY2tQYXRoKVxuICAgICAgICBwdWJsaXNoZWQgPSB0cnVlXG4gICAgICAgIHJldHVybiB0cnVlXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBjb2RlID0gLyoqIEB0eXBlIHtFcnJvciAmIHtjb2RlPzogc3RyaW5nfX0gKi8gKGVycm9yKT8uY29kZVxuXG4gICAgICAgIGlmIChjb2RlID09PSBcIkVFWElTVFwiIHx8IGNvZGUgPT09IFwiRU5PVEVNUFRZXCIpIHJldHVybiBmYWxzZVxuICAgICAgICB0aHJvdyBlcnJvclxuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICBpZiAoIXB1Ymxpc2hlZCkgYXdhaXQgZnMucm0oY2FuZGlkYXRlUGF0aCwge3JlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWV9KVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydHMgbGVhc2UgcmVuZXdhbCBmb3IgYSBmcmVzaGx5IGFjcXVpcmVkIGhvbGQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7dHJ1ZX0gLSBBbHdheXMgdHJ1ZTsgdGhlIGhvbGQgaXMgbm93IHRyYWNrZWQuXG4gICAqL1xuICBzdGFydEhvbGQobmFtZSkge1xuICAgIGNvbnN0IHRpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgdm9pZCB0aGlzLnJlbmV3SG9sZChuYW1lKVxuICAgIH0sIHRoaXMucmVuZXdJbnRlcnZhbE1zKVxuXG4gICAgaWYgKHR5cGVvZiB0aW1lci51bnJlZiA9PT0gXCJmdW5jdGlvblwiKSB0aW1lci51bnJlZigpXG5cbiAgICB0aGlzLmhvbGRzQnlOYW1lLnNldChuYW1lLCB7dGltZXJ9KVxuXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRlbmRzIHRoaXMgaW5zdGFuY2UncyBsZWFzZSBvbiBvbmUgaGVsZCBsb2NrOyBzdG9wcyByZW5ld2luZyB3aGVuIHRoZVxuICAgKiBkaXJlY3RvcnkgaXMgbm8gbG9uZ2VyIG91cnMgKHRoZSBsb2NrIHdhcyByZWNsYWltZWQpLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIExvY2sgbmFtZS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gUmVzb2x2ZXMgYWZ0ZXIgdGhlIHJlbmV3YWwgYXR0ZW1wdC5cbiAgICovXG4gIGFzeW5jIHJlbmV3SG9sZChuYW1lKSB7XG4gICAgY29uc3QgaG9sZCA9IHRoaXMuaG9sZHNCeU5hbWUuZ2V0KG5hbWUpXG5cbiAgICBpZiAoIWhvbGQpIHJldHVyblxuXG4gICAgY29uc3Qgb3duZXIgPSBhd2FpdCB0aGlzLnJlYWRPd25lcih0aGlzLmxvY2tQYXRoRm9yKG5hbWUpKVxuXG4gICAgaWYgKCFvd25lciB8fCBvd25lci5ob2xkZXJJZCAhPT0gdGhpcy5ob2xkZXJJZCkge1xuICAgICAgdGhpcy5jbGVhckhvbGQobmFtZSlcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGF3YWl0IHRoaXMud3JpdGVPd25lcih0aGlzLmxvY2tQYXRoRm9yKG5hbWUpKVxuICB9XG5cbiAgLyoqXG4gICAqIENsZWFycyB0aGUgcmVuZXdhbCB0aW1lciBmb3Igb25lIGhvbGQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gTG9jayBuYW1lLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIGNsZWFySG9sZChuYW1lKSB7XG4gICAgY29uc3QgaG9sZCA9IHRoaXMuaG9sZHNCeU5hbWUuZ2V0KG5hbWUpXG5cbiAgICBpZiAoIWhvbGQpIHJldHVyblxuXG4gICAgY2xlYXJJbnRlcnZhbChob2xkLnRpbWVyKVxuICAgIHRoaXMuaG9sZHNCeU5hbWUuZGVsZXRlKG5hbWUpXG4gIH1cblxuICAvKipcbiAgICogV3JpdGVzIG93bmVyICsgbGVhc2UgbWV0YWRhdGEgaW50byBhIGxvY2sgZGlyZWN0b3J5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbG9ja0RpclBhdGggLSBMb2NrIGRpcmVjdG9yeSB0byB3cml0ZSBtZXRhZGF0YSBpbnRvLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyBhZnRlciBtZXRhZGF0YSBpcyB3cml0dGVuLlxuICAgKi9cbiAgYXN5bmMgd3JpdGVPd25lcihsb2NrRGlyUGF0aCkge1xuICAgIC8qKiBAdHlwZSB7QWR2aXNvcnlMb2NrRmlsZU93bmVyfSAqL1xuICAgIGNvbnN0IG93bmVyID0ge1xuICAgICAgYWNxdWlyZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgaG9sZGVySWQ6IHRoaXMuaG9sZGVySWQsXG4gICAgICBob3N0bmFtZTogb3MuaG9zdG5hbWUoKSxcbiAgICAgIGxlYXNlRXhwaXJlc0F0OiBuZXcgRGF0ZShEYXRlLm5vdygpICsgdGhpcy5sZWFzZU1zKS50b0lTT1N0cmluZygpLFxuICAgICAgcGlkOiBwcm9jZXNzLnBpZCxcbiAgICAgIC4uLnRoaXMuZXh0cmFPd25lckZpZWxkc1xuICAgIH1cblxuICAgIGF3YWl0IGZzLndyaXRlRmlsZShwYXRoLmpvaW4obG9ja0RpclBhdGgsIFwib3duZXIuanNvblwiKSwgSlNPTi5zdHJpbmdpZnkob3duZXIpKVxuICB9XG5cbiAgLyoqXG4gICAqIFJlYWRzIG93bmVyIG1ldGFkYXRhIGZyb20gYSBsb2NrIGRpcmVjdG9yeS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGxvY2tQYXRoIC0gTG9jayBkaXJlY3RvcnkgcGF0aC5cbiAgICogQHJldHVybnMge1Byb21pc2U8QWR2aXNvcnlMb2NrRmlsZU93bmVyIHwgbnVsbD59IC0gUGFyc2VkIG93bmVyIG1ldGFkYXRhLCB3aGVuIHJlYWRhYmxlLlxuICAgKi9cbiAgYXN5bmMgcmVhZE93bmVyKGxvY2tQYXRoKSB7XG4gICAgLyoqIEB0eXBlIHtzdHJpbmd9ICovXG4gICAgbGV0IHJhd093bmVyXG5cbiAgICB0cnkge1xuICAgICAgcmF3T3duZXIgPSBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4obG9ja1BhdGgsIFwib3duZXIuanNvblwiKSwgXCJ1dGY4XCIpXG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICByZXR1cm4gLyoqIEB0eXBlIHtBZHZpc29yeUxvY2tGaWxlT3duZXJ9ICovIChKU09OLnBhcnNlKHJhd093bmVyKSlcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEEgbG9jayBkaXJlY3RvcnkgaXMgc3RhbGUgd2hlbiBpdHMgbWV0YWRhdGEgaXMgdW5yZWFkYWJsZSwgaXRzIGxlYXNlIGhhc1xuICAgKiBleHBpcmVkLCBvciBpdHMgb3duZXIgaXMgYSBkZWFkIHByb2Nlc3Mgb24gdGhpcyBob3N0LiBDcm9zcy1ob3N0IG93bmVyc1xuICAgKiBhcmUgb25seSByZWNsYWltYWJsZSB2aWEgbGVhc2UgZXhwaXJ5IOKAlCBQSUQgcHJvYmluZyBpcyB1bnJlbGlhYmxlIGJleW9uZFxuICAgKiBvbmUgaG9zdCwgd2hpY2ggaXMgZXhhY3RseSB3aHkgdGhpcyB0aWVyIGlzIHRoZSBvcHQtaW4gc2luZ2xlLWhvc3QgbGFzdFxuICAgKiByZXNvcnQgKGRlc2lnbiDCpzQvwqc4KS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGxvY2tQYXRoIC0gTG9jayBkaXJlY3RvcnkgcGF0aC5cbiAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IC0gV2hldGhlciB0aGUgbG9jayBjYW4gYmUgcmVjbGFpbWVkLlxuICAgKi9cbiAgYXN5bmMgaXNTdGFsZShsb2NrUGF0aCkge1xuICAgIGNvbnN0IG93bmVyID0gYXdhaXQgdGhpcy5yZWFkT3duZXIobG9ja1BhdGgpXG5cbiAgICBpZiAoIW93bmVyIHx8IHR5cGVvZiBvd25lci5waWQgIT09IFwibnVtYmVyXCIpIHJldHVybiB0cnVlXG5cbiAgICBpZiAob3duZXIubGVhc2VFeHBpcmVzQXQgJiYgbmV3IERhdGUob3duZXIubGVhc2VFeHBpcmVzQXQpLmdldFRpbWUoKSA8PSBEYXRlLm5vdygpKSByZXR1cm4gdHJ1ZVxuXG4gICAgaWYgKG93bmVyLmhvc3RuYW1lICYmIG93bmVyLmhvc3RuYW1lICE9PSBvcy5ob3N0bmFtZSgpKSByZXR1cm4gZmFsc2VcblxuICAgIHRyeSB7XG4gICAgICAvLyBga2lsbChwaWQsIDApYCBpcyBhIG5vLW9wIHNpZ25hbCB0aGF0IGZhaWxzIHdpdGggRVNSQ0ggd2hlbiB0aGVcbiAgICAgIC8vIHByb2Nlc3MgaXMgZ29uZTsgcGVybWlzc2lvbiBlcnJvcnMgc3RpbGwgcHJvdmUgdGhlIHByb2Nlc3MgZXhpc3RzLlxuICAgICAgcHJvY2Vzcy5raWxsKG93bmVyLnBpZCwgMClcblxuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiAvKiogQHR5cGUge0Vycm9yICYge2NvZGU/OiBzdHJpbmd9fSAqLyAoZXJyb3IpLmNvZGUgPT09IFwiRVNSQ0hcIlxuICAgIH1cbiAgfVxufVxuIl19
|
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
export type AdvisoryLockBackendProvenance = {
|
|
2
|
+
/**
|
|
3
|
+
* - Tier that served the acquisition.
|
|
4
|
+
*/
|
|
5
|
+
backend: import("./advisory-lock-backend-policy.js").AdvisoryLockTier;
|
|
6
|
+
/**
|
|
7
|
+
* - Database driver type when the driver tier served it.
|
|
8
|
+
*/
|
|
9
|
+
driverType?: string;
|
|
10
|
+
/**
|
|
11
|
+
* - Whether this tier carries fencing tokens (design §8); the file tier reports false rather than pretending.
|
|
12
|
+
*/
|
|
13
|
+
fencingSupported: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* - Backend holder id for the file tier.
|
|
16
|
+
*/
|
|
17
|
+
holderId?: string;
|
|
18
|
+
/**
|
|
19
|
+
* - Lock name this provenance belongs to.
|
|
20
|
+
*/
|
|
21
|
+
lockName?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Provenance of one advisory-lock acquisition (STC-210 design §3): every
|
|
25
|
+
* held lock reports the tier that actually served it, so a fallback is
|
|
26
|
+
* visible to the callback, in logs, and in `getAdvisoryLockBackendStatus()`.
|
|
27
|
+
* @typedef {object} AdvisoryLockBackendProvenance
|
|
28
|
+
* @property {import("./advisory-lock-backend-policy.js").AdvisoryLockTier} backend - Tier that served the acquisition.
|
|
29
|
+
* @property {string} [driverType] - Database driver type when the driver tier served it.
|
|
30
|
+
* @property {boolean} fencingSupported - Whether this tier carries fencing tokens (design §8); the file tier reports false rather than pretending.
|
|
31
|
+
* @property {string} [holderId] - Backend holder id for the file tier.
|
|
32
|
+
* @property {string} [lockName] - Lock name this provenance belongs to.
|
|
33
|
+
*/
|
|
1
34
|
/**
|
|
2
35
|
* Thrown when an advisory lock could not be acquired before `timeoutMs` elapsed.
|
|
3
36
|
*/
|
|
@@ -69,12 +102,13 @@ export default class AdvisoryLockRunner {
|
|
|
69
102
|
* cleanup can release the lock even if callback database work is stuck.
|
|
70
103
|
* @template T
|
|
71
104
|
* @param {string} name - Lock name.
|
|
72
|
-
* @param {(args?: {control
|
|
105
|
+
* @param {(args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>} callback - Callback to invoke while the lock is held.
|
|
73
106
|
* @param {{timeoutMs?: number | null, holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - Lock and hold timeout options.
|
|
74
107
|
* @returns {Promise<T>} - Resolves with the callback result.
|
|
75
108
|
*/
|
|
76
109
|
withAdvisoryLock<T>(name: string, callback: (args?: {
|
|
77
|
-
control
|
|
110
|
+
control?: import("awaitery/build/timeout.js").TimeoutControl;
|
|
111
|
+
lockBackend: AdvisoryLockBackendProvenance;
|
|
78
112
|
}) => Promise<T>, args?: {
|
|
79
113
|
timeoutMs?: number | null;
|
|
80
114
|
holdTimeoutMs?: number | null;
|
|
@@ -89,16 +123,18 @@ export default class AdvisoryLockRunner {
|
|
|
89
123
|
* cancellation.
|
|
90
124
|
* @template T
|
|
91
125
|
* @param {string} name - Lock name.
|
|
92
|
-
* @param {(args?: {control
|
|
126
|
+
* @param {(args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>} callback - Callback to invoke while the lock is held.
|
|
93
127
|
* @param {{holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - Hold timeout options.
|
|
94
128
|
* @returns {Promise<T>} - Resolves with the callback result.
|
|
95
129
|
*/
|
|
96
130
|
withAdvisoryLockOrFail<T>(name: string, callback: (args?: {
|
|
97
|
-
control
|
|
131
|
+
control?: import("awaitery/build/timeout.js").TimeoutControl;
|
|
132
|
+
lockBackend: AdvisoryLockBackendProvenance;
|
|
98
133
|
}) => Promise<T>, args?: {
|
|
99
134
|
holdTimeoutMs?: number | null;
|
|
100
135
|
dedicatedConnection?: boolean;
|
|
101
136
|
}): Promise<T>;
|
|
137
|
+
/**
|
|
102
138
|
/**
|
|
103
139
|
* Runs a callback if the advisory lock can be acquired without waiting;
|
|
104
140
|
* otherwise returns a `{acquired: false}` defer result instead of throwing.
|
|
@@ -114,12 +150,13 @@ export default class AdvisoryLockRunner {
|
|
|
114
150
|
* file lock), so a caller never branches on the backend.
|
|
115
151
|
* @template T
|
|
116
152
|
* @param {string} name - Lock name.
|
|
117
|
-
* @param {(args?: {control
|
|
153
|
+
* @param {(args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>} callback - Callback to invoke while the lock is held.
|
|
118
154
|
* @param {{holdTimeoutMs?: number | null, dedicatedConnection?: boolean}} [args] - Hold timeout options.
|
|
119
155
|
* @returns {Promise<{acquired: true, result: T} | {acquired: false, reason: "contended", lockName: string}>} - Either the held-callback result or the defer outcome.
|
|
120
156
|
*/
|
|
121
157
|
withAdvisoryLockOrDefer<T>(name: string, callback: (args?: {
|
|
122
|
-
control
|
|
158
|
+
control?: import("awaitery/build/timeout.js").TimeoutControl;
|
|
159
|
+
lockBackend: AdvisoryLockBackendProvenance;
|
|
123
160
|
}) => Promise<T>, args?: {
|
|
124
161
|
holdTimeoutMs?: number | null;
|
|
125
162
|
dedicatedConnection?: boolean;
|
|
@@ -132,19 +169,73 @@ export default class AdvisoryLockRunner {
|
|
|
132
169
|
lockName: string;
|
|
133
170
|
}>;
|
|
134
171
|
/**
|
|
135
|
-
* Runs the lock holder callback and releases the lock from its owning
|
|
172
|
+
* Runs the lock holder callback and releases the lock from its owning backend.
|
|
136
173
|
* @template T
|
|
137
|
-
* @param {{callback: (args?: {control
|
|
174
|
+
* @param {{callback: (args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>, holdTimeoutMs?: number | null, lockBackend: AdvisoryLockBackendProvenance, name: string, release: () => Promise<unknown>}} args - Locked callback args.
|
|
138
175
|
* @returns {Promise<T>} - Resolves with the callback result.
|
|
139
176
|
*/
|
|
140
|
-
runLockedCallback<T>({ callback,
|
|
177
|
+
runLockedCallback<T>({ callback, holdTimeoutMs, lockBackend, name, release }: {
|
|
141
178
|
callback: (args?: {
|
|
142
|
-
control
|
|
179
|
+
control?: import("awaitery/build/timeout.js").TimeoutControl;
|
|
180
|
+
lockBackend: AdvisoryLockBackendProvenance;
|
|
143
181
|
}) => Promise<T>;
|
|
144
|
-
connection: import("./drivers/base.js").default;
|
|
145
182
|
holdTimeoutMs?: number | null;
|
|
183
|
+
lockBackend: AdvisoryLockBackendProvenance;
|
|
146
184
|
name: string;
|
|
185
|
+
release: () => Promise<unknown>;
|
|
147
186
|
}): Promise<T>;
|
|
187
|
+
/**
|
|
188
|
+
* Resolves the backend policy for one lock name and returns the file
|
|
189
|
+
* backend when the name explicitly opts into the file tier
|
|
190
|
+
* (`preferredTier: "file"` plus `advisoryLocks.backends.file.enabled: true`).
|
|
191
|
+
* A name whose declared minimum tier is cross-host is refused loudly
|
|
192
|
+
* (`AdvisoryLockMinTierRefusedError`) before any contact with the file
|
|
193
|
+
* tier. A name that prefers the file tier while the backend is disabled
|
|
194
|
+
* moves to the driver path (a stronger-or-equal tier), never the other way
|
|
195
|
+
* around. Nothing here ever auto-enables the file tier.
|
|
196
|
+
* @param {string} name - Lock name.
|
|
197
|
+
* @returns {Promise<import("./advisory-lock-file-backend.js").default | null>} - Resolves with the file backend serving this name, or null for the driver path.
|
|
198
|
+
*/
|
|
199
|
+
fileBackendForName(name: string): Promise<import("./advisory-lock-file-backend.js").default | null>;
|
|
200
|
+
/**
|
|
201
|
+
* Fail-closed check on the driver path (design §9): an undeclared lock name
|
|
202
|
+
* keeps today's behavior (any driver serves it — full backward
|
|
203
|
+
* compatibility), but a name with an explicit policy entry is refused with
|
|
204
|
+
* `AdvisoryLockBackendUnavailableError` when the configured driver cannot
|
|
205
|
+
* satisfy its minimum tier (e.g. `minTier: "driver-native"` on a SQLite
|
|
206
|
+
* driver, which has no native advisory-lock primitive).
|
|
207
|
+
* @param {string} name - Lock name.
|
|
208
|
+
* @param {AdvisoryLockBackendProvenance} lockBackend - Tier the driver path would serve with.
|
|
209
|
+
* @returns {void}
|
|
210
|
+
*/
|
|
211
|
+
assertDriverTierEligible(name: string, lockBackend: AdvisoryLockBackendProvenance): void;
|
|
212
|
+
/**
|
|
213
|
+
* Resolves the wait bound for a file-tier acquisition: an explicit caller
|
|
214
|
+
* `timeoutMs` (including an explicit `null` opt-out) wins, otherwise the
|
|
215
|
+
* same framework default that bounds driver acquisitions applies.
|
|
216
|
+
* @param {{timeoutMs?: number | null}} args - Lock options.
|
|
217
|
+
* @returns {number | null} - Wait bound in milliseconds, or `null` for an indefinite wait.
|
|
218
|
+
*/
|
|
219
|
+
fileAcquireTimeoutMs(args: {
|
|
220
|
+
timeoutMs?: number | null;
|
|
221
|
+
}): number | null;
|
|
222
|
+
/**
|
|
223
|
+
* Builds the acquisition provenance for a file-tier hold. The file tier
|
|
224
|
+
* cannot carry fencing tokens, so the limitation is reported on every
|
|
225
|
+
* acquisition rather than silently pretended away (design §8).
|
|
226
|
+
* @param {import("./advisory-lock-file-backend.js").default} backend - Backend that served the acquisition.
|
|
227
|
+
* @param {string} name - Lock name.
|
|
228
|
+
* @returns {AdvisoryLockBackendProvenance} - Acquisition provenance.
|
|
229
|
+
*/
|
|
230
|
+
fileProvenance(backend: import("./advisory-lock-file-backend.js").default, name: string): AdvisoryLockBackendProvenance;
|
|
231
|
+
/**
|
|
232
|
+
* Builds the acquisition provenance for a driver-served hold. SQLite has no
|
|
233
|
+
* native advisory-lock primitive, so its emulation tier is reported as
|
|
234
|
+
* `process-local` rather than pretending to be database-native.
|
|
235
|
+
* @param {import("./drivers/base.js").default} connection - Connection that served the acquisition.
|
|
236
|
+
* @returns {AdvisoryLockBackendProvenance} - Acquisition provenance.
|
|
237
|
+
*/
|
|
238
|
+
driverProvenance(connection: import("./drivers/base.js").default): AdvisoryLockBackendProvenance;
|
|
148
239
|
/**
|
|
149
240
|
* Runs lock work on the caller connection unless `dedicatedConnection` is
|
|
150
241
|
* requested or a positive hold timeout needs its own lock connection.
|
|
@@ -172,16 +263,26 @@ export default class AdvisoryLockRunner {
|
|
|
172
263
|
*
|
|
173
264
|
* The callback receives a `TimeoutControl` from awaitery, enabling cooperative
|
|
174
265
|
* cancellation via `control.check()`, `control.signal`, `control.timedOut`,
|
|
175
|
-
* and `control.remaining()
|
|
266
|
+
* and `control.remaining()`, plus `lockBackend` provenance for the tier that
|
|
267
|
+
* served the acquisition.
|
|
176
268
|
* @template T
|
|
177
269
|
* @param {string} name - Lock name (for the error message).
|
|
178
|
-
* @param {(args?: {control
|
|
270
|
+
* @param {(args?: {control?: import("awaitery/build/timeout.js").TimeoutControl, lockBackend: AdvisoryLockBackendProvenance}) => Promise<T>} callback - Callback holding the lock.
|
|
179
271
|
* @param {number | null} [holdTimeoutMs] - Max hold time; falsy disables the timeout.
|
|
272
|
+
* @param {AdvisoryLockBackendProvenance} [lockBackend] - Provenance of the acquisition serving this hold.
|
|
180
273
|
* @returns {Promise<T>} - Resolves with the callback result.
|
|
181
274
|
*/
|
|
182
275
|
static runWithAdvisoryLockHoldTimeout<T>(name: string, callback: (args?: {
|
|
183
|
-
control
|
|
184
|
-
|
|
276
|
+
control?: import("awaitery/build/timeout.js").TimeoutControl;
|
|
277
|
+
lockBackend: AdvisoryLockBackendProvenance;
|
|
278
|
+
}) => Promise<T>, holdTimeoutMs?: number | null, lockBackend?: AdvisoryLockBackendProvenance): Promise<T>;
|
|
279
|
+
/**
|
|
280
|
+
* Neutral provenance for direct `runWithAdvisoryLockHoldTimeout` callers that
|
|
281
|
+
* hold a lock acquired outside this runner.
|
|
282
|
+
* @returns {AdvisoryLockBackendProvenance} - Provenance with an unknown tier.
|
|
283
|
+
*/
|
|
284
|
+
static unknownBackendProvenance(): AdvisoryLockBackendProvenance;
|
|
185
285
|
}
|
|
186
286
|
export { AdvisoryLockBusyError, AdvisoryLockHoldTimeoutError, AdvisoryLockTimeoutError };
|
|
287
|
+
export { AdvisoryLockBackendUnavailableError, AdvisoryLockMinTierRefusedError } from "./advisory-lock-backend-policy.js";
|
|
187
288
|
//# sourceMappingURL=advisory-lock-runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advisory-lock-runner.d.ts","sourceRoot":"","sources":["../../../src/database/advisory-lock-runner.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"advisory-lock-runner.d.ts","sourceRoot":"","sources":["../../../src/database/advisory-lock-runner.js"],"names":[],"mappings":"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"}
|