@@ -10,6 +10,7 @@ use api::ElectrumApi;
10
10
use batch:: Batch ;
11
11
use config:: Config ;
12
12
use raw_client:: * ;
13
+ use std:: convert:: TryFrom ;
13
14
use types:: * ;
14
15
15
16
/// Generalized Electrum client that supports multiple backends. This wraps
@@ -52,12 +53,17 @@ macro_rules! impl_inner_call {
52
53
return res;
53
54
} ,
54
55
Err ( e) => {
55
- warn!( "call retry:{}/{} {:?}" , errors. len( ) + 1 , $self. config. retry( ) , e) ;
56
- errors. push( e) ;
57
- if errors. len( ) as u8 == $self. config. retry( ) {
56
+ let failed_attempts = errors. len( ) + 1 ;
57
+
58
+ if retries_exhausted( failed_attempts, $self. config. retry( ) ) {
59
+ warn!( "call '{}' failed after {} attempts" , stringify!( $name) , failed_attempts) ;
58
60
return Err ( Error :: AllAttemptsErrored ( errors) ) ;
59
61
}
60
62
63
+ warn!( "call '{}' failed with {}, retry: {}/{}" , stringify!( $name) , e, failed_attempts, $self. config. retry( ) ) ;
64
+
65
+ errors. push( e) ;
66
+
61
67
// Only one thread will try to recreate the client getting the write lock,
62
68
// other eventual threads will get Err and will block at the beginning of
63
69
// previous loop when trying to read()
@@ -71,11 +77,16 @@ macro_rules! impl_inner_call {
71
77
break ;
72
78
} ,
73
79
Err ( e) => {
74
- warn!( "client retry:{}/{} {:?}" , errors. len( ) + 1 , $self. config. retry( ) , e) ;
75
- errors. push( e) ;
76
- if errors. len( ) as u8 == $self. config. retry( ) {
80
+ let failed_attempts = errors. len( ) + 1 ;
81
+
82
+ if retries_exhausted( failed_attempts, $self. config. retry( ) ) {
83
+ warn!( "re-creating client failed after {} attempts" , failed_attempts) ;
77
84
return Err ( Error :: AllAttemptsErrored ( errors) ) ;
78
85
}
86
+
87
+ warn!( "re-creating client failed with {}, retry: {}/{}" , e, failed_attempts, $self. config. retry( ) ) ;
88
+
89
+ errors. push( e) ;
79
90
}
80
91
}
81
92
}
@@ -86,6 +97,13 @@ macro_rules! impl_inner_call {
86
97
}
87
98
}
88
99
100
+ fn retries_exhausted ( failed_attempts : usize , configured_retries : u8 ) -> bool {
101
+ match u8:: try_from ( failed_attempts) {
102
+ Ok ( failed_attempts) => failed_attempts > configured_retries,
103
+ Err ( _) => true , // if the usize doesn't fit into a u8, we definitely exhausted our retries
104
+ }
105
+ }
106
+
89
107
impl ClientType {
90
108
/// Constructor that supports multiple backends and allows configuration through
91
109
/// the [Config]
@@ -289,3 +307,38 @@ impl ElectrumApi for Client {
289
307
impl_inner_call ! ( self , calls_made)
290
308
}
291
309
}
310
+
311
+ #[ cfg( test) ]
312
+ mod tests {
313
+ use super :: * ;
314
+
315
+ #[ test]
316
+ fn more_failed_attempts_than_retries_means_exhausted ( ) {
317
+ let exhausted = retries_exhausted ( 10 , 5 ) ;
318
+
319
+ assert_eq ! ( exhausted, true )
320
+ }
321
+
322
+ #[ test]
323
+ fn failed_attempts_bigger_than_u8_means_exhausted ( ) {
324
+ let failed_attempts = u8:: MAX as usize + 1 ;
325
+
326
+ let exhausted = retries_exhausted ( failed_attempts, u8:: MAX ) ;
327
+
328
+ assert_eq ! ( exhausted, true )
329
+ }
330
+
331
+ #[ test]
332
+ fn less_failed_attempts_means_not_exhausted ( ) {
333
+ let exhausted = retries_exhausted ( 2 , 5 ) ;
334
+
335
+ assert_eq ! ( exhausted, false )
336
+ }
337
+
338
+ #[ test]
339
+ fn attempts_equals_retries_means_not_exhausted_yet ( ) {
340
+ let exhausted = retries_exhausted ( 2 , 2 ) ;
341
+
342
+ assert_eq ! ( exhausted, false )
343
+ }
344
+ }
0 commit comments