LibraryManager icon indicating copy to clipboard operation
LibraryManager copied to clipboard

Errors running libman CLI commands as a pre-build step in projects building in parallel on an Azure hosted agent

Open spongessuck opened this issue 5 years ago • 1 comments

Functional impact

Running into errors building projects in parallel on an Azure Pipelines hosted agent when they both invoke the libman CLI as a pre-build step.

Minimal repro steps

  1. Create a Visual Studio solution with 2 projects that both invoke "libman clean && libman restore" as a pre-build step
  2. Create an Azure Pipeline that
    1. Uses a 'dotnet' task to install the libman CLI to Agent.ToolsDirectory dotnet tool install Microsoft.Web.LibraryManager.Cli --tool-path="$(Agent.ToolsDirectory)"
    2. Uses a 'Powershell' task that adds Agent.ToolsDirectory to the environment variables Write-Host "##vso[task.setvariable variable=PATH;]${env:PATH};$(Agent.ToolsDirectory)";
    3. Builds the solution in parallel
  3. Run the build on an Azure hosted agent

Expected result

Libman CLI commands run successfully

Actual result

Sometimes I see the following error output for one of the projects which causes the build to fail:

Unhandled Exception: System.TypeInitializationException: The type initializer for 'Microsoft.Web.LibraryManager.Configuration.Settings' threw an exception. ---> System.IO.IOException: The process cannot access the file 'C:\Users\VssAdministrator\.librarymanager\libman.config.json' because it is being used by another process.

Further technical details

I assume the issue is because both commands are running simultaneously and one puts a lock on libman.config.json so the other can't access it. I have run the build on a VM agent and do not see this error, though I installed libman globally on that machine so the 'install Libman CLI' step isn't part of the pipeline that runs on it.

spongessuck avatar Oct 24 '19 15:10 spongessuck

Any chance you can get a callstack for the inner IOException? It seems like this could happen if they both try to create the file at the same time, since StreamWriter by default places a read lock when creating the file - i.e. if both tried to open the StreamWriter stream at the same time, maybe that's why we see this conflict?

If that is the case, one workaround would be to run any libman command earlier in the build (even libman --help) as that would create the settings file. The default initialization code will try to read the file, and multiple concurrent readers should be fine if the file exists and is valid.

jimmylewis avatar Nov 02 '19 07:11 jimmylewis