@@ -47,6 +47,8 @@ pub enum SyncError {
47
47
InvalidPushFrameNoLow ( u32 , u32 ) ,
48
48
#[ error( "server returned a higher frame_no: sent={0}, got={1}" ) ]
49
49
InvalidPushFrameNoHigh ( u32 , u32 ) ,
50
+ #[ error( "failed to pull frame: status={0}, error={1}" ) ]
51
+ PullFrame ( StatusCode , String ) ,
50
52
}
51
53
52
54
impl SyncError {
@@ -104,6 +106,21 @@ impl SyncContext {
104
106
Ok ( me)
105
107
}
106
108
109
+ #[ tracing:: instrument( skip( self ) ) ]
110
+ pub ( crate ) async fn pull_one_frame ( & mut self , generation : u32 , frame_no : u32 ) -> Result < Bytes > {
111
+ let uri = format ! (
112
+ "{}/sync/{}/{}/{}" ,
113
+ self . sync_url,
114
+ generation,
115
+ frame_no,
116
+ frame_no + 1
117
+ ) ;
118
+ tracing:: debug!( "pulling frame" ) ;
119
+ let frame = self . pull_with_retry ( uri, self . max_retries ) . await ?;
120
+ self . durable_frame_num = frame_no;
121
+ Ok ( frame)
122
+ }
123
+
107
124
#[ tracing:: instrument( skip( self , frame) ) ]
108
125
pub ( crate ) async fn push_one_frame (
109
126
& mut self ,
@@ -215,6 +232,53 @@ impl SyncContext {
215
232
}
216
233
}
217
234
235
+ async fn pull_with_retry ( & self , uri : String , max_retries : usize ) -> Result < Bytes > {
236
+ let mut nr_retries = 0 ;
237
+ loop {
238
+ let mut req = http:: Request :: builder ( ) . method ( "GET" ) . uri ( uri. clone ( ) ) ;
239
+
240
+ match & self . auth_token {
241
+ Some ( auth_token) => {
242
+ req = req. header ( "Authorization" , auth_token) ;
243
+ }
244
+ None => { }
245
+ }
246
+
247
+ let req = req. body ( Body :: empty ( ) )
248
+ . expect ( "valid request" ) ;
249
+
250
+ let res = self
251
+ . client
252
+ . request ( req)
253
+ . await
254
+ . map_err ( SyncError :: HttpDispatch ) ?;
255
+
256
+ if res. status ( ) . is_success ( ) {
257
+ let frame = hyper:: body:: to_bytes ( res. into_body ( ) )
258
+ . await
259
+ . map_err ( SyncError :: HttpBody ) ?;
260
+ return Ok ( frame) ;
261
+ }
262
+ // If we've retried too many times or the error is not a server error,
263
+ // return the error.
264
+ if nr_retries > max_retries || !res. status ( ) . is_server_error ( ) {
265
+ let status = res. status ( ) ;
266
+
267
+ let res_body = hyper:: body:: to_bytes ( res. into_body ( ) )
268
+ . await
269
+ . map_err ( SyncError :: HttpBody ) ?;
270
+
271
+ let msg = String :: from_utf8_lossy ( & res_body[ ..] ) ;
272
+
273
+ return Err ( SyncError :: PullFrame ( status, msg. to_string ( ) ) . into ( ) ) ;
274
+ }
275
+
276
+ let delay = std:: time:: Duration :: from_millis ( 100 * ( 1 << nr_retries) ) ;
277
+ tokio:: time:: sleep ( delay) . await ;
278
+ nr_retries += 1 ;
279
+ }
280
+ }
281
+
218
282
pub ( crate ) fn durable_frame_num ( & self ) -> u32 {
219
283
self . durable_frame_num
220
284
}
0 commit comments