Updater Application Block 2.0 and BITS: resume partial downloads

Problem
 
UAB does not resume broken downloads (due to connection failure or user cancelling the download).
 
Solution
 
These are the two changes to do in the BitsDownloader class
 
1. On the OnJobError method we need to NOT cancel the BITS job if the state is ERROR:
 
if( state != BG_JOB_STATE.BG_JOB_STATE_ACKNOWLEDGED &&
     state != BG_JOB_STATE.BG_JOB_STATE_CANCELLED &&
     state != BG_JOB_STATE.BG_JOB_STATE_TRANSFERRING &&      // don't interrupt downloads in progress
     state != BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED &&      // don't cancel a finished download
     state != BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR &&   // don't cancel when connection problems
     state != BG_JOB_STATE.BG_JOB_STATE_ERROR ) {            // don't cancel when connection problems
     pJob.Cancel();
 }
 
2. On the CheckForResumeAndProceed method check to see if the job is in ERROR or TRANSIENT_ERROR state and resume it. Why add this here? Because this method checks if there is a pending job. If there is a pending job and its state is ERROR, that means that the pending job failed due to a network failuire, or user aborted the application. If we call Resume BITS try to connect again. It will try to connect for 5 secs (NoProgressTimeout constant). If it couldn't do it, the job will stay in ERROR state. If not, it will transfer from the last byte transferred.
The code in bold letter need to be added
 
if ( jobState == BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED )
{
       OnJobTransferred( task, copyJob );
       return true;
}
if ( jobState == BG_JOB_STATE.BG_JOB_STATE_ERROR || jobState == BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR ) {
       copyJob.Resume();
}
 
Observations
  • This new code was tested in this scenarios: stopping the website; disabling the network card and aborting the application in the middle of the job, and it worked on all the scenarios. The job was resumed from the last byte transfered
  •  It's important to attach to the PendingUpdatesDetected event of the ApplicationUpdaterManager. On the handler of this event call ResumePendingUpdates. This is important because this method deserializes the tasks that holds the BITS Job ID previously aborted.
  • It is not recommended to debug the WaitForDownload method due to concurrency and sync issues. Instead, tracing is recommended. A simple tracing could be implemented to troubleshoot, just by using the Logger.LogInformation method that will write to the Event Viewer.

Published: January 05 2006

  • tags:
blog comments powered by Disqus