@microsoft/node-core-library
Advanced tools
Comparing version 0.5.1 to 0.6.0
@@ -5,2 +5,14 @@ { | ||
{ | ||
"version": "0.6.0", | ||
"tag": "@microsoft/node-core-library_v0.6.0", | ||
"date": "Fri, 16 Feb 2018 22:05:23 GMT", | ||
"comments": { | ||
"minor": [ | ||
{ | ||
"comment": "Add an API to `LockFile` which allows the caller to asyncronously wait for a LockFile to become available." | ||
} | ||
] | ||
} | ||
}, | ||
{ | ||
"version": "0.5.1", | ||
@@ -7,0 +19,0 @@ "tag": "@microsoft/node-core-library_v0.5.1", |
# Change Log - @microsoft/node-core-library | ||
This log was last generated on Fri, 16 Feb 2018 17:05:11 GMT and should not be manually modified. | ||
This log was last generated on Fri, 16 Feb 2018 22:05:23 GMT and should not be manually modified. | ||
## 0.6.0 | ||
Fri, 16 Feb 2018 22:05:23 GMT | ||
### Minor changes | ||
- Add an API to `LockFile` which allows the caller to asyncronously wait for a LockFile to become available. | ||
## 0.5.1 | ||
@@ -6,0 +13,0 @@ Fri, 16 Feb 2018 17:05:11 GMT |
@@ -257,2 +257,11 @@ /** | ||
/** | ||
* Attempts to create the lockfile. | ||
* Will continue to loop at every 100ms until the lock becomes available or the maxWaitMs is surpassed. | ||
* @remarks This function is subject to starvation, whereby it does not ensure that the process that has been | ||
* waiting the longest to acquire the lock will get it first. This means that a process could theoretically | ||
* wait for the lock forever, while other processes skipped it in line and acquired the lock first. | ||
*/ | ||
static acquire(resourceDir: string, resourceName: string, maxWaitMs?: number): Promise<LockFile>; | ||
private static _sleepForMs(timeout); | ||
/** | ||
* Attempts to acquire the lock on a Linux or OSX machine | ||
@@ -259,0 +268,0 @@ */ |
@@ -29,2 +29,11 @@ /** | ||
/** | ||
* Attempts to create the lockfile. | ||
* Will continue to loop at every 100ms until the lock becomes available or the maxWaitMs is surpassed. | ||
* @remarks This function is subject to starvation, whereby it does not ensure that the process that has been | ||
* waiting the longest to acquire the lock will get it first. This means that a process could theoretically | ||
* wait for the lock forever, while other processes skipped it in line and acquired the lock first. | ||
*/ | ||
static acquire(resourceDir: string, resourceName: string, maxWaitMs?: number): Promise<LockFile>; | ||
private static _sleepForMs(timeout); | ||
/** | ||
* Attempts to acquire the lock on a Linux or OSX machine | ||
@@ -31,0 +40,0 @@ */ |
@@ -8,2 +8,3 @@ "use strict"; | ||
const child_process = require("child_process"); | ||
const timers_1 = require("timers"); | ||
/** | ||
@@ -59,5 +60,5 @@ * Helper function that is exported for unit tests only. | ||
static getLockFilePath(resourceDir, resourceName, pid = process.pid) { | ||
if (!resourceName.match(/^[a-zA-Z]+$/)) { | ||
if (!resourceName.match(/^[a-zA-Z0-9][a-zA-Z0-9-.]+[a-zA-Z0-9]$/)) { | ||
throw new Error(`The resource name "${resourceName}" is invalid.` | ||
+ ` It must be an alphabetic string with no special characters.`); | ||
+ ` It must be an alphanumberic string with only "-" or "." It must start with an alphanumeric character.`); | ||
} | ||
@@ -68,3 +69,3 @@ if (process.platform === 'win32') { | ||
else if (process.platform === 'linux' || process.platform === 'darwin') { | ||
return path.join(path.resolve(resourceDir), `${resourceName}.${pid}.lock`); | ||
return path.join(path.resolve(resourceDir), `${resourceName}#${pid}.lock`); | ||
} | ||
@@ -89,2 +90,33 @@ throw new Error(`File locking not implemented for platform: "${process.platform}"`); | ||
/** | ||
* Attempts to create the lockfile. | ||
* Will continue to loop at every 100ms until the lock becomes available or the maxWaitMs is surpassed. | ||
* @remarks This function is subject to starvation, whereby it does not ensure that the process that has been | ||
* waiting the longest to acquire the lock will get it first. This means that a process could theoretically | ||
* wait for the lock forever, while other processes skipped it in line and acquired the lock first. | ||
*/ | ||
static acquire(resourceDir, resourceName, maxWaitMs) { | ||
const interval = 100; | ||
const startTime = Date.now(); | ||
const retryLoop = () => { | ||
const lock = LockFile.tryAcquire(resourceDir, resourceName); | ||
if (lock) { | ||
return Promise.resolve(lock); | ||
} | ||
if (maxWaitMs && (Date.now() > startTime + maxWaitMs)) { | ||
return Promise.reject(new Error(`Exceeded maximum wait time to acquire lock for resource "${resourceName}"`)); | ||
} | ||
return LockFile._sleepForMs(interval).then(() => { | ||
return retryLoop(); | ||
}); | ||
}; | ||
return retryLoop(); | ||
} | ||
static _sleepForMs(timeout) { | ||
return new Promise((resolve, reject) => { | ||
timers_1.setTimeout(() => { | ||
resolve(); | ||
}, timeout); | ||
}); | ||
} | ||
/** | ||
* Attempts to acquire the lock on a Linux or OSX machine | ||
@@ -114,4 +146,4 @@ */ | ||
const files = fsx.readdirSync(resourceDir); | ||
// look for anything ending with numbers and ".lock" | ||
const lockFileRegExp = /^([a-zA-Z]+)\.([0-9]+)\.lock$/; | ||
// look for anything ending with # then numbers and ".lock" | ||
const lockFileRegExp = /^(.+)#([0-9]+)\.lock$/; | ||
let match; | ||
@@ -118,0 +150,0 @@ let otherPid; |
@@ -20,15 +20,27 @@ "use strict"; | ||
it('only acceps alphabetical characters for resource name', () => { | ||
chai_1.assert.throws(() => { | ||
chai_1.assert.doesNotThrow(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), 'foo123'); | ||
}); | ||
chai_1.assert.throws(() => { | ||
chai_1.assert.doesNotThrow(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), 'bar.123'); | ||
}); | ||
chai_1.assert.throws(() => { | ||
chai_1.assert.doesNotThrow(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), 'foo.bar'); | ||
}); | ||
chai_1.assert.doesNotThrow(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), 'lock-file.123'); | ||
}); | ||
chai_1.assert.throws(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), 'lock-file'); | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), '.foo123'); | ||
}); | ||
chai_1.assert.throws(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), 'foo123.'); | ||
}); | ||
chai_1.assert.throws(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), '-foo123'); | ||
}); | ||
chai_1.assert.throws(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), 'foo123-'); | ||
}); | ||
chai_1.assert.throws(() => { | ||
LockFile_1.LockFile.getLockFilePath(process.cwd(), ''); | ||
@@ -42,6 +54,6 @@ }); | ||
it('returns a resolved path containing the pid', () => { | ||
chai_1.assert.equal(path.join(process.cwd(), `test.${process.pid}.lock`), LockFile_1.LockFile.getLockFilePath('./', 'test')); | ||
chai_1.assert.equal(path.join(process.cwd(), `test#${process.pid}.lock`), LockFile_1.LockFile.getLockFilePath('./', 'test')); | ||
}); | ||
it('allows for overridden pid', () => { | ||
chai_1.assert.equal(path.join(process.cwd(), `test.99.lock`), LockFile_1.LockFile.getLockFilePath('./', 'test', 99)); | ||
chai_1.assert.equal(path.join(process.cwd(), `test#99.lock`), LockFile_1.LockFile.getLockFilePath('./', 'test', 99)); | ||
}); | ||
@@ -48,0 +60,0 @@ }); |
{ | ||
"name": "@microsoft/node-core-library", | ||
"version": "0.5.1", | ||
"version": "0.6.0", | ||
"description": "Core libraries that every NodeJS toolchain project should use", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
179498
2222