@azure/msal-node-extensions
Version:
 
96 lines (93 loc) • 3.8 kB
JavaScript
/*! @azure/msal-node-extensions v1.5.9 2025-03-25 */
;
import { promises } from 'fs';
import { pid } from 'process';
import { Constants } from '../utils/Constants.mjs';
import { PersistenceError } from '../error/PersistenceError.mjs';
import { isNodeError } from '../utils/TypeGuards.mjs';
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
/**
* Cross-process lock that works on all platforms.
*/
class CrossPlatformLock {
constructor(lockFilePath, logger, lockOptions) {
this.lockFilePath = lockFilePath;
this.retryNumber = lockOptions ? lockOptions.retryNumber : 500;
this.retryDelay = lockOptions ? lockOptions.retryDelay : 100;
this.logger = logger;
}
/**
* Locks cache from read or writes by creating file with same path and name as
* cache file but with .lockfile extension. If another process has already created
* the lockfile, will back off and retry based on configuration settings set by CrossPlatformLockOptions
*/
async lock() {
for (let tryCount = 0; tryCount < this.retryNumber; tryCount++) {
try {
this.logger.info(`Pid ${pid} trying to acquire lock`);
this.lockFileHandle = await promises.open(this.lockFilePath, "wx+");
this.logger.info(`Pid ${pid} acquired lock`);
await this.lockFileHandle.write(pid.toString());
return;
}
catch (err) {
if (isNodeError(err)) {
if (err.code === Constants.EEXIST_ERROR ||
err.code === Constants.EPERM_ERROR) {
this.logger.info(err.message);
await this.sleep(this.retryDelay);
}
else {
this.logger.error(`${pid} was not able to acquire lock. Ran into error: ${err.message}`);
throw PersistenceError.createCrossPlatformLockError(err.message);
}
}
else {
throw err;
}
}
}
this.logger.error(`${pid} was not able to acquire lock. Exceeded amount of retries set in the options`);
throw PersistenceError.createCrossPlatformLockError("Not able to acquire lock. Exceeded amount of retries set in options");
}
/**
* unlocks cache file by deleting .lockfile.
*/
async unlock() {
try {
if (this.lockFileHandle) {
// if we have a file handle to the .lockfile, delete lock file
await promises.unlink(this.lockFilePath);
await this.lockFileHandle.close();
this.logger.info("lockfile deleted");
}
else {
this.logger.warning("lockfile handle does not exist, so lockfile could not be deleted");
}
}
catch (err) {
if (isNodeError(err)) {
if (err.code === Constants.ENOENT_ERROR) {
this.logger.info("Tried to unlock but lockfile does not exist");
}
else {
this.logger.error(`${pid} was not able to release lock. Ran into error: ${err.message}`);
throw PersistenceError.createCrossPlatformLockError(err.message);
}
}
else {
throw err;
}
}
}
sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
}
export { CrossPlatformLock };
//# sourceMappingURL=CrossPlatformLock.mjs.map