@azure/msal-node-extensions error deleting lockfile in Artillery.io
See original GitHub issueCore Library
Core Library Version
1.0.2
Wrapper Library
Not Applicable
Wrapper Library Version
None
Description
I am using @azure/msal-node and msal-node-extensions (FilePersistenceWithDataProtection) in my Artillery.io load test script (via custom JavaScript). When I have simulated users arrive at a high rate (e.g., 100 per second), and all of them start by acquiring access tokens via acquireTokenByUsernamePassword, I get this error thrown from msal-node-extensions:
(node:4488) UnhandledPromiseRejectionWarning: PersistenceError: CrossPlatformLockError: EPERM: operation not permitted, unlink ‘(path to lockfile)’
I know that this is not a true permissions problem because when I lower the arrival rate to say, 10 per second, everything works fine. It looks to me like the FilePersistenceWithDataProtection logic for deleting the lockfile doesn’t handle the case where it is called concurrently at a high rate in a single calling process. I have attached a sample script that doesn’t require Artillery and simply uses setInterval to acquire 100 tokens per second - this reproduces the problem.
Error Message
(node:4488) UnhandledPromiseRejectionWarning: PersistenceError: CrossPlatformLockError: EPERM: operation not permitted, unlink ‘C:\RDS\intelliv8\patents\LoadTest\msal.cache.lockfile’ at Function.createCrossPlatformLockError (C:\RDS\intelliv8\patents\LoadTest\node_modules@azure\msal-node-extensions\dist\msal-node-extensions.cjs.development.js:989:12) at CrossPlatformLock._callee2$ (C:\RDS\intelliv8\patents\LoadTest\node_modules@azure\msal-node-extensions\dist\msal-node-extensions.cjs.development.js:1144:38) at tryCatch (C:\RDS\intelliv8\patents\LoadTest\node_modules@azure\msal-node-extensions\dist\msal-node-extensions.cjs.development.js:211:40) at Generator.invoke [as _invoke] (C:\RDS\intelliv8\patents\LoadTest\node_modules@azure\msal-node-extensions\dist\msal-node-extensions.cjs.development.js:441:22) at Generator.throw (C:\RDS\intelliv8\patents\LoadTest\node_modules@azure\msal-node-extensions\dist\msal-node-extensions.cjs.development.js:266:21) at asyncGeneratorStep (C:\RDS\intelliv8\patents\LoadTest\node_modules@azure\msal-node-extensions\dist\msal-node-extensions.cjs.development.js:13:24) at _throw (C:\RDS\intelliv8\patents\LoadTest\node_modules@azure\msal-node-extensions\dist\msal-node-extensions.cjs.development.js:39:9)
Msal Logs
No response
MSAL Configuration
please see the attached code snippet
Relevant Code Snippets
const fs = require("fs")
const msal = require("@azure/msal-node")
const { FilePersistenceWithDataProtection, DataProtectionScope, PersistenceCachePlugin } = require("@azure/msal-node-extensions")
const CACHE_PATH = "./msal.cache"
const CLIENT_ID = ""
const INSTANCE = ""
const TENANT_ID = ""
const USERNAME = ""
const PASSWORD = ""
let msalConfig = null
let clientApp = null
async function init(
cachePath,
clientId,
instance,
tenantId)
{
const windowsPersistence = await FilePersistenceWithDataProtection.create(
cachePath,
DataProtectionScope.CurrentUser)
msalConfig =
{
auth:
{
clientId,
authority: instance + tenantId,
},
cache:
{
cachePlugin: new PersistenceCachePlugin(windowsPersistence)
}
}
clientApp = new msal.PublicClientApplication(msalConfig)
}
async function getAccessToken(
username,
password)
{
const request =
{
scopes: [msalConfig.auth.clientId + "/.default"],
}
let response
const accounts = await clientApp.getTokenCache().getAllAccounts()
const account = accounts.find(acc => acc.username === username)
if(account != null)
{
request.account = account
response = await clientApp.acquireTokenSilent(request)
}
else
{
request.username = username
request.password = password
response = await clientApp.acquireTokenByUsernamePassword(request)
}
return response.accessToken
}
async function setupBeforeTesting()
{
if(fs.existsSync(CACHE_PATH))
fs.unlinkSync(CACHE_PATH)
await init(
CACHE_PATH,
CLIENT_ID,
INSTANCE,
TENANT_ID)
}
async function test()
{
await setupBeforeTesting()
setInterval(() =>
{
getAccessToken(USERNAME, PASSWORD)
},
10)
}
test()
Reproduction Steps
I reproduced this on Windows with Node.js 14.16
- Edit the test script to supply CLIENT_ID and the other required constants.
npm install @azure/msal-node @azure/msal-node-extensions
node test.js
Expected Behavior
I expected it to handle any arbitrary concurrent call rate without failing.
Identity Provider
Azure AD / MSA
Browsers Affected (Select all that apply)
None (Server)
Regression
No response
Source
External (Customer)
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (5 by maintainers)
Top GitHub Comments
@samuelkubai Thanks for that clarification. Thinking about your comment, I realized that for my Artillery use case I don’t actually need a file cache for MSAL since everything is running in a single process. So I have worked around this issue by removing the cache, and it seems to work fine with large numbers of concurrent virtual users.
Closing this.