@@ -21,21 +21,20 @@ use risingwave_common::monitor::{EndpointExt, TcpConfig};
21
21
use risingwave_common:: util:: addr:: HostAddr ;
22
22
use risingwave_pb:: frontend_service:: frontend_service_client:: FrontendServiceClient ;
23
23
use risingwave_pb:: frontend_service:: { GetTableReplacePlanRequest , GetTableReplacePlanResponse } ;
24
+ use tokio_retry:: strategy:: { jitter, ExponentialBackoff } ;
24
25
use tonic:: transport:: Endpoint ;
26
+ use tonic:: Response ;
25
27
26
28
use crate :: error:: Result ;
27
29
use crate :: tracing:: { Channel , TracingInjectedChannelExt } ;
28
- use crate :: { frontend_rpc_client_method_impl , RpcClient , RpcClientPool } ;
30
+ use crate :: { RpcClient , RpcClientPool } ;
29
31
30
- #[ derive( Clone ) ]
31
- pub struct FrontendClient ( FrontendServiceClient < Channel > ) ;
32
+ const DEFAULT_RETRY_INTERVAL : u64 = 50 ;
33
+ const DEFAULT_RETRY_MAX_DELAY : Duration = Duration :: from_secs ( 5 ) ;
34
+ const DEFAULT_RETRY_MAX_ATTEMPTS : usize = 10 ;
32
35
33
- #[ async_trait]
34
- impl RpcClient for FrontendClient {
35
- async fn new_client ( host_addr : HostAddr ) -> Result < Self > {
36
- Self :: new ( host_addr) . await
37
- }
38
- }
36
+ #[ derive( Clone ) ]
37
+ struct FrontendClient ( FrontendServiceClient < Channel > ) ;
39
38
40
39
impl FrontendClient {
41
40
async fn new ( host_addr : HostAddr ) -> Result < Self > {
@@ -59,17 +58,61 @@ impl FrontendClient {
59
58
}
60
59
61
60
// similar to the stream_client used in the Meta node
62
- pub type FrontendClientPool = RpcClientPool < FrontendClient > ;
61
+ pub type FrontendClientPool = RpcClientPool < FrontendRetryClient > ;
63
62
pub type FrontendClientPoolRef = Arc < FrontendClientPool > ;
64
63
65
- macro_rules! for_all_frontend_rpc {
66
- ( $macro: ident) => {
67
- $macro! {
68
- { 0 , get_table_replace_plan, GetTableReplacePlanRequest , GetTableReplacePlanResponse }
69
- }
70
- } ;
64
+ #[ async_trait]
65
+ impl RpcClient for FrontendRetryClient {
66
+ async fn new_client ( host_addr : HostAddr ) -> Result < Self > {
67
+ Self :: new ( host_addr) . await
68
+ }
71
69
}
72
70
73
- impl FrontendClient {
74
- for_all_frontend_rpc ! { frontend_rpc_client_method_impl }
71
+ #[ derive( Clone ) ]
72
+ pub struct FrontendRetryClient {
73
+ client : FrontendClient ,
74
+ }
75
+
76
+ impl FrontendRetryClient {
77
+ async fn new ( host_addr : HostAddr ) -> Result < Self > {
78
+ let client = FrontendClient :: new ( host_addr) . await ?;
79
+ Ok ( Self { client } )
80
+ }
81
+
82
+ #[ inline( always) ]
83
+ fn get_retry_strategy ( ) -> impl Iterator < Item = Duration > {
84
+ ExponentialBackoff :: from_millis ( DEFAULT_RETRY_INTERVAL )
85
+ . max_delay ( DEFAULT_RETRY_MAX_DELAY )
86
+ . take ( DEFAULT_RETRY_MAX_ATTEMPTS )
87
+ . map ( jitter)
88
+ }
89
+
90
+ fn should_retry ( status : & tonic:: Status ) -> bool {
91
+ if status. code ( ) == tonic:: Code :: Unavailable
92
+ || status. code ( ) == tonic:: Code :: Unknown
93
+ || status. code ( ) == tonic:: Code :: Unauthenticated
94
+ || status. code ( ) == tonic:: Code :: Aborted
95
+ {
96
+ return true ;
97
+ }
98
+ false
99
+ }
100
+
101
+ pub async fn get_table_replace_plan (
102
+ & self ,
103
+ request : GetTableReplacePlanRequest ,
104
+ ) -> std:: result:: Result < Response < GetTableReplacePlanResponse > , tonic:: Status > {
105
+ tokio_retry:: RetryIf :: spawn (
106
+ Self :: get_retry_strategy ( ) ,
107
+ || async {
108
+ self . client
109
+ . to_owned ( )
110
+ . 0
111
+ . get_table_replace_plan ( request. clone ( ) )
112
+ . await
113
+ } ,
114
+ Self :: should_retry,
115
+ )
116
+ . await
117
+ }
75
118
}
0 commit comments