Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSBuild - wait for x seconds

Tags:

msbuild

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>
like image 807
Ben Cameron Avatar asked Dec 16 '16 16:12

Ben Cameron


2 Answers

There are multiple options available:

  1. MSBuild Community Tasks has built-in Sleep task. You can use it like this:

    <Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets" />
    <Sleep Milliseconds="300" />
    
  2. MSBuild Extension Pack also contains built-in Thread task which offers Sleep functionality. Example of usage is here.

  3. Of course any kind of cmd-compatible wait can work as well via Exec command:

    • Already mentioned <Exec Command="ping -n 6 127.0.0.1 > nul" />
    • I also had <Exec Command="sleep 5" /> worked for me nicely.
  4. 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"/>
    
like image 95
Igor Labutin Avatar answered Oct 14 '22 01:10

Igor Labutin


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.

like image 39
stijn Avatar answered Oct 14 '22 01:10

stijn