@@ -10,6 +10,7 @@ use tokio::sync::{mpsc, oneshot, watch, Semaphore};
10
10
use crate :: Error ;
11
11
12
12
const QUEUE_SIZE : usize = 100 ;
13
+ const MAX_RETRIES : usize = 3 ;
13
14
14
15
#[ derive( Debug ) ]
15
16
struct DownloadRequest {
@@ -18,6 +19,7 @@ struct DownloadRequest {
18
19
result : oneshot:: Sender < Result < File , Error > > ,
19
20
status : watch:: Sender < Status > ,
20
21
cancel : oneshot:: Receiver < ( ) > ,
22
+ remaining_retries : usize ,
21
23
}
22
24
23
25
#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
@@ -55,6 +57,7 @@ pub enum Status {
55
57
Pending ,
56
58
InProgress ( DownloadProgress ) ,
57
59
Completed ,
60
+ Retrying ,
58
61
Cancelled ,
59
62
Failed ,
60
63
}
@@ -109,6 +112,7 @@ impl DownloadManager {
109
112
result : result_tx,
110
113
status : status_tx,
111
114
cancel : cancel_rx,
115
+ remaining_retries : MAX_RETRIES ,
112
116
} ;
113
117
114
118
let _ = self . queue . try_send ( req) ;
@@ -126,7 +130,7 @@ async fn dispatcher_thread(
126
130
mut rx : mpsc:: Receiver < DownloadRequest > ,
127
131
sem : Arc < Semaphore > ,
128
132
) {
129
- while let Some ( request) = rx. recv ( ) . await {
133
+ while let Some ( mut request) = rx. recv ( ) . await {
130
134
let permit = match sem. clone ( ) . acquire_owned ( ) . await {
131
135
Ok ( permit) => permit,
132
136
Err ( _) => break ,
@@ -135,24 +139,33 @@ async fn dispatcher_thread(
135
139
tokio:: spawn ( async move {
136
140
// Move the permit into the worker thread so it's automatically released when the thread finishes
137
141
let _permit = permit;
138
- match download_thread ( client, & request) . await {
139
- Ok ( file) => {
140
- let _ = request. status . send ( Status :: Completed ) ;
141
- let _ = request. result . send ( Ok ( file) ) ;
142
- }
143
- Err ( e) => {
144
- let status = match e {
145
- Error :: Io ( ref io_err) => {
146
- if io_err. kind ( ) == std:: io:: ErrorKind :: Interrupted {
147
- Status :: Cancelled
148
- } else {
149
- Status :: Failed
150
- }
142
+ loop {
143
+ match download_thread ( client. clone ( ) , & request) . await {
144
+ Ok ( file) => {
145
+ let _ = request. status . send ( Status :: Completed ) ;
146
+ let _ = request. result . send ( Ok ( file) ) ;
147
+ break ;
148
+ }
149
+ Err ( e) => {
150
+ if request. remaining_retries > 0 {
151
+ let _ = request. status . send ( Status :: Retrying ) ;
152
+ request. remaining_retries -= 1 ;
153
+ } else {
154
+ let status = match e {
155
+ Error :: Io ( ref io_err) => {
156
+ if io_err. kind ( ) == std:: io:: ErrorKind :: Interrupted {
157
+ Status :: Cancelled
158
+ } else {
159
+ Status :: Failed
160
+ }
161
+ }
162
+ _ => Status :: Failed ,
163
+ } ;
164
+ let _ = request. status . send ( status) ;
165
+ let _ = request. result . send ( Err ( e) ) ;
166
+ break ;
151
167
}
152
- _ => Status :: Failed ,
153
- } ;
154
- let _ = request. status . send ( status) ;
155
- let _ = request. result . send ( Err ( e) ) ;
168
+ }
156
169
}
157
170
}
158
171
} ) ;
0 commit comments