@@ -3,7 +3,6 @@ use tracing::warn;
3
3
use crate :: { data_state:: CanMakeProgress , Awaiting , DataState , ErrorBounds } ;
4
4
use std:: fmt:: Debug ;
5
5
use std:: ops:: Range ;
6
- use std:: time:: { Duration , Instant } ;
7
6
8
7
/// Automatically retries with a delay on failure until attempts are exhausted
9
8
#[ derive( Debug ) ]
@@ -17,7 +16,7 @@ pub struct DataStateRetry<T, E: ErrorBounds = anyhow::Error> {
17
16
18
17
attempts_left : u8 ,
19
18
inner : DataState < T , E > , // Not public to ensure resets happen as they should
20
- next_allowed_attempt : Instant ,
19
+ next_allowed_attempt : u128 ,
21
20
}
22
21
23
22
impl < T , E : ErrorBounds > DataStateRetry < T , E > {
@@ -35,9 +34,8 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
35
34
self . attempts_left
36
35
}
37
36
38
- /// The instant that needs to be waited for before another attempt is
39
- /// allowed
40
- pub fn next_allowed_attempt ( & self ) -> Instant {
37
+ /// The number of millis after the epoch that an attempt is allowed
38
+ pub fn next_allowed_attempt ( & self ) -> u128 {
41
39
self . next_allowed_attempt
42
40
}
43
41
@@ -112,7 +110,7 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
112
110
format ! (
113
111
"{} attempt(s) left. {} seconds before retry. {e}" ,
114
112
self . attempts_left,
115
- wait_left. as_secs ( )
113
+ wait_left / 1000
116
114
) ,
117
115
) ;
118
116
if ui. button ( "Stop Trying" ) . clicked ( ) {
@@ -140,12 +138,9 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
140
138
DataState :: None => {
141
139
// Going to make an attempt, set when the next attempt is allowed
142
140
use rand:: Rng as _;
143
- let wait_time_in_millis = rand:: thread_rng ( )
144
- . gen_range ( self . retry_delay_millis . clone ( ) )
145
- . into ( ) ;
146
- self . next_allowed_attempt = Instant :: now ( )
147
- . checked_add ( Duration :: from_millis ( wait_time_in_millis) )
148
- . expect ( "failed to get random delay, value was out of range" ) ;
141
+ let wait_time_in_millis =
142
+ rand:: thread_rng ( ) . gen_range ( self . retry_delay_millis . clone ( ) ) ;
143
+ self . next_allowed_attempt = millis_since_epoch ( ) + wait_time_in_millis as u128 ;
149
144
150
145
self . inner . start_request ( fetch_fn)
151
146
}
@@ -162,7 +157,7 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
162
157
CanMakeProgress :: UnableToMakeProgress
163
158
} else {
164
159
let wait_left = wait_before_next_attempt ( self . next_allowed_attempt ) ;
165
- if wait_left. is_zero ( ) {
160
+ if wait_left == 0 {
166
161
warn ! ( ?err_msg, ?self . attempts_left, "retrying request" ) ;
167
162
self . attempts_left -= 1 ;
168
163
self . inner = DataState :: None ;
@@ -176,7 +171,7 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
176
171
/// Resets the attempts taken
177
172
pub fn reset_attempts ( & mut self ) {
178
173
self . attempts_left = self . max_attempts ;
179
- self . next_allowed_attempt = Instant :: now ( ) ;
174
+ self . next_allowed_attempt = millis_since_epoch ( ) ;
180
175
}
181
176
182
177
/// Clear stored data
@@ -214,7 +209,7 @@ impl<T, E: ErrorBounds> Default for DataStateRetry<T, E> {
214
209
max_attempts : 3 ,
215
210
retry_delay_millis : 1000 ..5000 ,
216
211
attempts_left : 3 ,
217
- next_allowed_attempt : Instant :: now ( ) ,
212
+ next_allowed_attempt : millis_since_epoch ( ) ,
218
213
}
219
214
}
220
215
}
@@ -232,8 +227,15 @@ impl<T, E: ErrorBounds> AsMut<DataStateRetry<T, E>> for DataStateRetry<T, E> {
232
227
}
233
228
234
229
/// The duration before the next attempt will be made
235
- fn wait_before_next_attempt ( next_allowed_attempt : Instant ) -> Duration {
236
- next_allowed_attempt. saturating_duration_since ( Instant :: now ( ) )
230
+ fn wait_before_next_attempt ( next_allowed_attempt : u128 ) -> u128 {
231
+ next_allowed_attempt. saturating_sub ( millis_since_epoch ( ) )
232
+ }
233
+
234
+ fn millis_since_epoch ( ) -> u128 {
235
+ web_time:: SystemTime :: UNIX_EPOCH
236
+ . elapsed ( )
237
+ . expect ( "expected date on system to be after the epoch" )
238
+ . as_millis ( )
237
239
}
238
240
239
241
// TODO 4: Use mocking to add tests ensuring retires are executed
0 commit comments