@@ -47,6 +47,8 @@ pub enum SyncError {
4747 InvalidPushFrameNoLow ( u32 , u32 ) ,
4848 #[ error( "server returned a higher frame_no: sent={0}, got={1}" ) ]
4949 InvalidPushFrameNoHigh ( u32 , u32 ) ,
50+ #[ error( "failed to pull frame: status={0}, error={1}" ) ]
51+ PullFrame ( StatusCode , String ) ,
5052}
5153
5254impl SyncError {
@@ -104,6 +106,21 @@ impl SyncContext {
104106 Ok ( me)
105107 }
106108
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+
107124 #[ tracing:: instrument( skip( self , frame) ) ]
108125 pub ( crate ) async fn push_one_frame (
109126 & mut self ,
@@ -215,6 +232,53 @@ impl SyncContext {
215232 }
216233 }
217234
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+
218282 pub ( crate ) fn durable_frame_num ( & self ) -> u32 {
219283 self . durable_frame_num
220284 }
0 commit comments