@sunerpy/opencode-kiro-auth 0.13.6 → 0.13.7
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.
|
@@ -5,16 +5,14 @@ import lockfile from 'proper-lockfile';
|
|
|
5
5
|
import { isPermanentError } from '../health.js';
|
|
6
6
|
import { getKeepAliveLockPath, getRefreshLockPath } from '../paths.js';
|
|
7
7
|
export { getKeepAliveLockPath, getRefreshLockPath } from '../paths.js';
|
|
8
|
-
const
|
|
8
|
+
const DATABASE_LOCK_OPTIONS = {
|
|
9
9
|
stale: 10000,
|
|
10
|
-
retries:
|
|
11
|
-
retries: 5,
|
|
12
|
-
minTimeout: 100,
|
|
13
|
-
maxTimeout: 1000,
|
|
14
|
-
factor: 2
|
|
15
|
-
},
|
|
10
|
+
retries: 0,
|
|
16
11
|
realpath: false
|
|
17
12
|
};
|
|
13
|
+
const DATABASE_LOCK_DEADLINE_MS = 10000;
|
|
14
|
+
const DATABASE_LOCK_MIN_BACKOFF_MS = 25;
|
|
15
|
+
const DATABASE_LOCK_MAX_BACKOFF_MS = 250;
|
|
18
16
|
const REFRESH_LOCK_OPTIONS = {
|
|
19
17
|
stale: 15000,
|
|
20
18
|
retries: {
|
|
@@ -38,6 +36,29 @@ function blockingBackoff(ms) {
|
|
|
38
36
|
function isLockContention(e) {
|
|
39
37
|
return typeof e === 'object' && e !== null && 'code' in e && e.code === 'ELOCKED';
|
|
40
38
|
}
|
|
39
|
+
function asyncBackoff(attempt, remainingMs) {
|
|
40
|
+
const ceiling = Math.min(DATABASE_LOCK_MIN_BACKOFF_MS * 2 ** Math.min(attempt, 4), DATABASE_LOCK_MAX_BACKOFF_MS, remainingMs);
|
|
41
|
+
const floor = Math.max(1, Math.floor(ceiling / 2));
|
|
42
|
+
const delay = floor + Math.floor(Math.random() * (ceiling - floor + 1));
|
|
43
|
+
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
44
|
+
}
|
|
45
|
+
async function acquireDatabaseLock(dbPath) {
|
|
46
|
+
// A deadline avoids fixed retry-count starvation; jitter keeps contenders
|
|
47
|
+
// from repeatedly attempting the atomic mkdir in lockstep.
|
|
48
|
+
const deadline = Date.now() + DATABASE_LOCK_DEADLINE_MS;
|
|
49
|
+
let attempt = 0;
|
|
50
|
+
for (;;) {
|
|
51
|
+
try {
|
|
52
|
+
return await lockfile.lock(dbPath, DATABASE_LOCK_OPTIONS);
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
const remainingMs = deadline - Date.now();
|
|
56
|
+
if (!isLockContention(e) || remainingMs <= 0)
|
|
57
|
+
throw e;
|
|
58
|
+
await asyncBackoff(attempt++, remainingMs);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
41
62
|
export function withDatabaseLockSync(dbPath, fn) {
|
|
42
63
|
if (!existsSync(dbPath)) {
|
|
43
64
|
mkdirSync(dirname(dbPath), { recursive: true });
|
|
@@ -73,13 +94,12 @@ export function withDatabaseLockSync(dbPath, fn) {
|
|
|
73
94
|
}
|
|
74
95
|
export async function withDatabaseLock(dbPath, fn) {
|
|
75
96
|
if (!existsSync(dbPath)) {
|
|
76
|
-
|
|
77
|
-
await fs.mkdir(dir, { recursive: true });
|
|
97
|
+
await fs.mkdir(dirname(dbPath), { recursive: true });
|
|
78
98
|
await fs.writeFile(dbPath, '');
|
|
79
99
|
}
|
|
80
100
|
let release = null;
|
|
81
101
|
try {
|
|
82
|
-
release = await
|
|
102
|
+
release = await acquireDatabaseLock(dbPath);
|
|
83
103
|
return await fn();
|
|
84
104
|
}
|
|
85
105
|
finally {
|