I have a MSBuild script that deploys a web app. It stops the current web app by copying a 'app_offline.htm' file to the server. After this it deletes other files then copies new ones to the server.
I need to add a delay between the copying of 'app_offline.htm' and the delete.
My current script throws errors as the files are still locked when the script tries to delete them.
What is the best way to do this in MSBuild?
My Stop task looks like this...
<Target Name="Stop">
<WriteLinesToFile File="$(DeployDirectory)\app_offline.htm" Lines="Offline for maintenance" Overwrite="true" Encoding="Unicode"/>
</Target>
My Delete task looks like this...
<Target Name="Clean">
<ItemGroup>
<Files Include="$(DeployDirectory)\**\*" Exclude="$(DeployDirectory)\app_offline.htm" />
<Files Include="$(LogDirectory)\*" />
</ItemGroup>
<Delete Files="@(Files)" />
</Target>
There are multiple options available:
MSBuild Community Tasks has built-in Sleep
task. You can use it like this:
<Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets" />
<Sleep Milliseconds="300" />
MSBuild Extension Pack also contains built-in Thread
task which offers Sleep functionality. Example of usage is here.
Of course any kind of cmd-compatible wait can work as well via Exec
command:
<Exec Command="ping -n 6 127.0.0.1 > nul" />
<Exec Command="sleep 5" />
worked for me nicely.You can define MSBuild inline C# task for that purpose:
<UsingTask TaskName="Sleep" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<!-- Delay in milliseconds -->
<Delay ParameterType="System.Int32" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
System.Threading.Thread.Sleep(this.Delay);
]]>
</Code>
</Task>
</UsingTask>
...
<Sleep Delay="5000"/>
You could use the Exec task to invoke one of the solutions from How to sleep for 5 seconds in Windows's Command Prompt? (or DOS), e.g. the ping is noniteractive so should work. Something like
<Exec Command="ping -n 6 127.0.0.1 > nul"/>
<Delete Files="@(Files)" />
Also see https://github.com/Microsoft/msbuild/issues/199: in the future the Delete task might get similar parameters as the Copy task has now. So another option is to use Copy with a retry count set to try to overwrite one of the files in use, and when that succeeds you know it's not in use anymore and can go on with the Delete:
<Copy SourceFiles="someFile" DestinationFile="$(DeployDirectory)\someFileInUse"
RetryDelayMilliseconds="1000" Retries="5"/>
<Delete Files="@(Files)" />
Of course both solutions fail if the timeout expires and the file is still in use but there's not which can be done about that without risking infinite waits.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With