Search code examples
powershellpowershell-remotingms-release-management

Release Management vNext Component Deployment Bottleneck


We're using Release Management 2015 with vNext release templates. We have a Powershell DSC based component deployment for each of the portions of our application, and in fact, we have two distinct applications being deployed and that are in active development and are often deployed at nearly the same time.

We very frequently get the following error during deployments:

OperationFailedException: New deployment is not allowed as an another deployment is in progress. Retry the deployment after sometime.

The full stack trace shows that the error is coming not from Powershell itself, but from Release Management's system that's in charge of execution of the powershell script on the target machine:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Microsoft.TeamFoundation.Release.Common.Helpers.OperationFailedException: New deployment is not allowed as an another deployment is in progress. Retry the deployment after sometime.
   at Microsoft.TeamFoundation.Release.EnvironmentProvider.OnPrem.Implementation.OnPremDeploymentProvider.ReadDeploymentResponse(DeploymentResponse response)
   at Microsoft.TeamFoundation.Release.EnvironmentProvider.OnPrem.Implementation.OnPremDeploymentProvider.RunScript(String scriptPath, String configurationPath, MachineSpecification machine, StorageSpecification storage, Dictionary`2 configurationVariables)
   at Microsoft.TeamFoundation.Release.MonitorServices.Dsc.OnPrem.OnPremDeploymentActions.InvokePlatform(String activityId, MachineSpecification machineSpecification, StorageSpecification storageSpecification, String scriptPath, String configurationPath, Dictionary`2 configurationVariables)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.TeamFoundation.Release.DeploymentAgent.Services.Deployer.Dsc.DscComponentInstaller.InvokeMethodByReflection(String methodArguments)

The above error causes the entire deployment to fail, and we're forced to retry the stage or the entire deployment to have it finish.

There are two scenarios that cause this:

  1. Two release templates execute their powershell scripts on the same target server at the same time
  2. A single release template has a parallel control flow which contains two different components that both execute scripts on the same target server

In other words, the mechanism that Release Management uses to execute a powershell script on a remote server can only seem to ever execute a single script at a time, and has no ability to wait/hold for others to complete.

This kinda/sorta makes sense if the script in question as actively modifying the server on which it's executing, but in our case, the server acts as basically a staging area to run the script. The "real" target of the script has nothing to do with the server on which the powershell happens to be executing.

Aside from having a server-per-simultaneously-deployed-component (wow), what's the work around here? It seems like a major oversight and it's seriously making me consider dropping Release Management altogether.


Solution

  • As I explained in another post today, MS Release Management's way of deploying is a bit counter-intuitive: Rather than just executing your Powershell deployment script against the target server using PSRemoting, it uses PSRemoting to install a Windows Service (VisualStudioRemoteDeployer.exe) on the target server. This service then runs your deployment script locally, and the MSRM server regularly polls this Windows service (see here) to see if it is finished deploying.

    I suspect this strange setup has something to do with avoiding the double-hop issue - so that it allows your script to make a 2nd hop from the target server to another server, e.g. for a webservice call.

    Anyway, this Windows service probably forms the bottleneck, because there can be only one such instance running per server - hence the fact that parallel deployments of components to the same server appear to collide.

    I think your problems originate from the fact that you chose a setup where "the server acts as basically a staging area to run the script" - MS Release Management 2013/2015 doesn't play well in this scenario (as you found out), you should really deploy your components directly to the target servers on which they need to be installed, thus avoiding the staging area bottleneck.

    The next version of MS Release Management will be using deployment agents that will serve as a staging point from which the components will be deployed to the other servers. This helps reducing the number of connections you have to allow on your firewall between the MS Release Management and the target servers (which is probably why you chose the staging area setup), while still allowing parallel (or at least queued) deployments.