d_engine_client/builder.rs
1use std::sync::Arc;
2use std::time::Duration;
3
4use arc_swap::ArcSwap;
5
6use super::Client;
7use super::ClientApiError;
8use super::ClientConfig;
9use super::ClientInner;
10use super::ConnectionPool;
11use super::GrpcClient;
12
13/// Configurable builder for [`Client`] instances
14///
15/// Implements the **builder pattern** for constructing clients with
16/// customized connection parameters and timeouts.
17///
18/// # Typical Usage Flow
19/// 1. Create with `ClientBuilder::new()`
20/// 2. Chain configuration methods
21/// 3. Finalize with `.build()`
22///
23/// # Default Configuration
24/// - Compression: Enabled
25/// - Connect Timeout: 1s
26/// - Request Timeout: 3s
27pub struct ClientBuilder {
28 config: ClientConfig,
29 endpoints: Vec<String>,
30}
31
32impl ClientBuilder {
33 /// Create a new builder with default config and specified endpoints
34 pub fn new(endpoints: Vec<String>) -> Self {
35 Self {
36 config: ClientConfig::default(),
37 endpoints,
38 }
39 }
40
41 /// Set connection timeout (default: 1s)
42 pub fn connect_timeout(
43 mut self,
44 timeout: Duration,
45 ) -> Self {
46 self.config.connect_timeout = timeout;
47 self
48 }
49
50 /// Set request timeout (default: 3s)
51 pub fn request_timeout(
52 mut self,
53 timeout: Duration,
54 ) -> Self {
55 self.config.request_timeout = timeout;
56 self
57 }
58
59 /// Set cluster ready timeout (default: 5s)
60 ///
61 /// Controls how long build() / refresh() waits for a leader to be elected
62 /// and its noop entry committed. Use shorter values for health checks,
63 /// longer values for production startup.
64 pub fn cluster_ready_timeout(
65 mut self,
66 timeout: Duration,
67 ) -> Self {
68 self.config.cluster_ready_timeout = timeout;
69 self
70 }
71
72 /// Enable/disable compression (default: enabled)
73 pub fn enable_compression(
74 mut self,
75 enable: bool,
76 ) -> Self {
77 self.config.enable_compression = enable;
78 self
79 }
80
81 /// Completely replaces the default configuration
82 ///
83 /// # Warning: Configuration Override
84 /// This will discard all previous settings configured through individual
85 /// methods like [`connect_timeout`](ClientBuilder::connect_timeout) or
86 /// [`enable_compression`](ClientBuilder::enable_compression).
87 ///
88 /// # Usage Guidance
89 /// Choose **either**:
90 /// - Use granular configuration methods (recommended for most cases)
91 /// - Use this method to provide a full configuration object
92 ///
93 /// # Example: Full Configuration
94 /// ```no_run
95 /// use d_engine_client::ClientBuilder;
96 /// use d_engine_client::ClientConfig;
97 /// use std::time::Duration;
98 ///
99 /// let custom_config = ClientConfig {
100 /// connect_timeout: Duration::from_secs(2),
101 /// request_timeout: Duration::from_secs(5),
102 /// ..ClientConfig::default()
103 /// };
104 ///
105 /// let builder = ClientBuilder::new(vec!["http://node1:9081".into()])
106 /// .set_config(custom_config);
107 /// ```
108 pub fn set_config(
109 mut self,
110 config: ClientConfig,
111 ) -> Self {
112 self.config = config;
113 self
114 }
115
116 /// Build the client with current configuration
117 pub async fn build(self) -> std::result::Result<Client, ClientApiError> {
118 let pool = ConnectionPool::create(self.endpoints.clone(), self.config.clone()).await?;
119 let client_inner = Arc::new(ArcSwap::from_pointee(ClientInner {
120 pool,
121 client_id: self.config.id,
122 config: self.config,
123 endpoints: self.endpoints,
124 }));
125
126 Ok(Client {
127 inner: Arc::new(GrpcClient::new(client_inner)),
128 })
129 }
130}