Updater Application Block 2.0 and BITS: resume partial downloads
January 5th, 2006
Problem
UAB does not resume
broken downloads (due to connection failure or user cancelling the
download).
broken downloads (due to connection failure or user cancelling the
download).
Solution
These are the two
changes to do in the BitsDownloader class
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:
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();
}
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.
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
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();
}
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.