( options: TryAcquireFsLockOptions, )
| 183 | } |
| 184 | |
| 185 | export async function tryAcquireFsLock( |
| 186 | options: TryAcquireFsLockOptions, |
| 187 | ): Promise<AcquiredFsLock | null> { |
| 188 | const now = options.now ?? Date.now(); |
| 189 | const owner: FsLockOwner = { |
| 190 | token: randomUUID(), |
| 191 | pid: options.pid ?? process.pid, |
| 192 | purpose: options.purpose, |
| 193 | acquiredAtMs: now, |
| 194 | expiresAtMs: now + options.leaseMs, |
| 195 | }; |
| 196 | |
| 197 | try { |
| 198 | await fs.mkdir(path.dirname(options.lockDir), { recursive: true, mode: 0o700 }); |
| 199 | const guard = await tryAcquireGuard(options.lockDir, options.purpose, options.leaseMs, now); |
| 200 | if (!guard) { |
| 201 | return null; |
| 202 | } |
| 203 | |
| 204 | try { |
| 205 | for (let attempt = 0; attempt < 2; attempt += 1) { |
| 206 | try { |
| 207 | return await createLock(options.lockDir, owner); |
| 208 | } catch (error) { |
| 209 | const code = (error as NodeJS.ErrnoException).code; |
| 210 | if (code !== 'EEXIST') { |
| 211 | return null; |
| 212 | } |
| 213 | |
| 214 | const recovered = await tryRecoverExpiredLockDir( |
| 215 | options.lockDir, |
| 216 | options.purpose, |
| 217 | now, |
| 218 | options.leaseMs, |
| 219 | ); |
| 220 | if (!recovered) { |
| 221 | return null; |
| 222 | } |
| 223 | } |
| 224 | } |
| 225 | } finally { |
| 226 | await guard.release(); |
| 227 | } |
| 228 | } catch { |
| 229 | return null; |
| 230 | } |
| 231 | |
| 232 | return null; |
| 233 | } |
no test coverage detected