@@ -20,6 +20,7 @@ use futures_util::{
2020} ;
2121use tokio:: task:: { JoinHandle , spawn_blocking} ;
2222use tracing:: { debug, info, warn} ;
23+ use url:: Url ;
2324
2425use crate :: {
2526 diskio:: { Executor , IO_CHUNK_SIZE , get_executor, unpack_ram} ,
@@ -771,32 +772,13 @@ impl<'a> ComponentBinary<'a> {
771772 }
772773
773774 async fn download ( self , max_retries : usize ) -> anyhow:: Result < ( ComponentInstall , & ' a str ) > {
774- use tokio_retry:: { RetryIf , strategy:: FixedInterval } ;
775-
776775 let url = self . download_cfg . url ( & self . binary . url ) ?;
777- let installer = RetryIf :: start (
778- FixedInterval :: from_millis ( 0 ) . take ( max_retries) ,
779- || {
780- self . download_cfg
781- . download ( & url, & self . binary . hash , & self . status )
782- } ,
783- |e : & anyhow:: Error | {
784- // retry only known retriable cases
785- match e. downcast_ref :: < RustupError > ( ) {
786- Some ( RustupError :: BrokenPartialFile )
787- | Some ( RustupError :: IncompletePartialFile )
788- | Some ( RustupError :: DownloadingFile { .. } ) => {
789- self . status . retrying ( ) ;
790- true
791- }
792- _ => false ,
793- }
794- } ,
795- )
796- . await
797- . with_context ( || {
798- RustupError :: ComponentDownloadFailed ( self . manifest . name ( & self . component ) )
799- } ) ?;
776+ let installer = self
777+ . download_with_retries ( & url, max_retries)
778+ . await
779+ . with_context ( || {
780+ RustupError :: ComponentDownloadFailed ( self . manifest . name ( & self . component ) )
781+ } ) ?;
800782
801783 let install = ComponentInstall {
802784 status : self . status ,
@@ -813,6 +795,44 @@ impl<'a> ComponentBinary<'a> {
813795
814796 Ok ( ( install, & self . binary . hash ) )
815797 }
798+
799+ async fn download_with_retries ( & self , url : & Url , max_retries : usize ) -> anyhow:: Result < File > {
800+ const MIN_PROGRESS : u64 = 1024 * 1024 ;
801+
802+ let mut retries = 0 ;
803+ loop {
804+ let downloaded = self . download_cfg . partial_len ( & self . binary . hash ) ;
805+ let err = match self
806+ . download_cfg
807+ . download ( url, & self . binary . hash , & self . status )
808+ . await
809+ {
810+ Ok ( file) => return Ok ( file) ,
811+ Err ( err) => err,
812+ } ;
813+
814+ // retry only known retriable cases
815+ match err. downcast_ref :: < RustupError > ( ) {
816+ Some ( RustupError :: BrokenPartialFile )
817+ | Some ( RustupError :: IncompletePartialFile )
818+ | Some ( RustupError :: DownloadingFile { .. } ) => { }
819+ _ => return Err ( err) ,
820+ }
821+
822+ let progress = self
823+ . download_cfg
824+ . partial_len ( & self . binary . hash )
825+ . saturating_sub ( downloaded) ;
826+ if progress < MIN_PROGRESS {
827+ if retries == max_retries {
828+ return Err ( err) ;
829+ }
830+ retries += 1 ;
831+ }
832+
833+ self . status . retrying ( ) ;
834+ }
835+ }
816836}
817837
818838struct ComponentInstall {
0 commit comments