redis_enterprise/
proxies.rs

1//! Proxies management for Redis Enterprise
2//!
3//! ## Overview
4//! - List and query resources
5//! - Create and update configurations
6//! - Monitor status and metrics
7
8use crate::client::RestClient;
9use crate::error::Result;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13/// Response for a single metric query
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct MetricResponse {
16    pub interval: String,
17    pub timestamps: Vec<i64>,
18    pub values: Vec<Value>,
19    #[serde(flatten)]
20    pub extra: Value,
21}
22
23/// Proxy information
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct Proxy {
26    pub uid: u32,
27    pub bdb_uid: u32,
28    pub node_uid: u32,
29    pub status: String,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub addr: Option<String>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub port: Option<u16>,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub max_connections: Option<u32>,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub threads: Option<u32>,
38
39    // Additional fields from API audit
40    /// Maximum number of pending connections in the listen queue
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub backlog: Option<u32>,
43
44    /// Whether automatic client eviction is enabled when limits are reached
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub client_eviction: Option<bool>,
47
48    /// Number of TCP keepalive probes before connection is dropped
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub client_keepcnt: Option<u32>,
51
52    /// Time in seconds before TCP keepalive probes start
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub client_keepidle: Option<u32>,
55
56    /// Interval in seconds between TCP keepalive probes
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub client_keepintvl: Option<u32>,
59
60    /// Current number of active connections
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub conns: Option<u32>,
63
64    /// Whether core dump files are generated on crash
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub corefile: Option<bool>,
67
68    /// Threshold in milliseconds for slow operation logging
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub duration_usage_threshold: Option<u32>,
71
72    /// Whether proxy can dynamically adjust thread count based on load
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub dynamic_threads_scaling: Option<bool>,
75
76    /// Whether to bypass database connection limit checks
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub ignore_bdb_cconn_limit: Option<bool>,
79
80    /// Whether to bypass database output buffer limit checks
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub ignore_bdb_cconn_output_buff_limits: Option<bool>,
83
84    /// Maximum capacity for incoming connection handling
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub incoming_connections_capacity: Option<u32>,
87
88    /// Minimum reserved capacity for incoming connections
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub incoming_connections_min_capacity: Option<u32>,
91
92    /// Maximum rate of new incoming connections per second
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub incoming_connections_rate_limit: Option<u32>,
95
96    /// Logging level for proxy (e.g., 'debug', 'info', 'warning', 'error')
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub log_level: Option<String>,
99
100    /// Maximum number of listener sockets
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub max_listeners: Option<u32>,
103
104    /// Maximum number of backend server connections
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub max_servers: Option<u32>,
107
108    /// Maximum number of worker threads
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub max_threads: Option<u32>,
111
112    /// Maximum client connections per worker thread
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub max_worker_client_conns: Option<u32>,
115
116    /// Maximum server connections per worker thread
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub max_worker_server_conns: Option<u32>,
119
120    /// Maximum concurrent transactions per worker thread
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub max_worker_txns: Option<u32>,
123
124    /// Maximum memory in bytes allocated for client connections
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub maxmemory_clients: Option<u32>,
127
128    /// CPU usage threshold percentage for thread scaling decisions
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub threads_usage_threshold: Option<u32>,
131
132    #[serde(flatten)]
133    pub extra: Value,
134}
135
136/// Proxy stats information
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct ProxyStats {
139    pub uid: u32,
140    pub intervals: Vec<StatsInterval>,
141
142    #[serde(flatten)]
143    pub extra: Value,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct StatsInterval {
148    pub interval: String,
149    pub timestamps: Vec<i64>,
150    pub values: Vec<Value>,
151}
152
153/// Proxy handler for managing proxies
154pub struct ProxyHandler {
155    client: RestClient,
156}
157
158impl ProxyHandler {
159    pub fn new(client: RestClient) -> Self {
160        ProxyHandler { client }
161    }
162
163    /// List all proxies
164    pub async fn list(&self) -> Result<Vec<Proxy>> {
165        self.client.get("/v1/proxies").await
166    }
167
168    /// Get specific proxy information
169    pub async fn get(&self, uid: u32) -> Result<Proxy> {
170        self.client.get(&format!("/v1/proxies/{}", uid)).await
171    }
172
173    /// Get proxy statistics
174    pub async fn stats(&self, uid: u32) -> Result<ProxyStats> {
175        self.client.get(&format!("/v1/proxies/{}/stats", uid)).await
176    }
177
178    /// Get proxy statistics for a specific metric
179    pub async fn stats_metric(&self, uid: u32, metric: &str) -> Result<MetricResponse> {
180        self.client
181            .get(&format!("/v1/proxies/{}/stats/{}", uid, metric))
182            .await
183    }
184
185    /// Get proxies for a specific database
186    pub async fn list_by_database(&self, bdb_uid: u32) -> Result<Vec<Proxy>> {
187        self.client
188            .get(&format!("/v1/bdbs/{}/proxies", bdb_uid))
189            .await
190    }
191
192    /// Get proxies for a specific node
193    pub async fn list_by_node(&self, node_uid: u32) -> Result<Vec<Proxy>> {
194        self.client
195            .get(&format!("/v1/nodes/{}/proxies", node_uid))
196            .await
197    }
198
199    /// Reload proxy configuration
200    pub async fn reload(&self, uid: u32) -> Result<()> {
201        self.client
202            .post_action(&format!("/v1/proxies/{}/actions/reload", uid), &Value::Null)
203            .await
204    }
205
206    /// Update proxies (bulk) - PUT /v1/proxies
207    pub async fn update_all(&self, update: ProxyUpdate) -> Result<Vec<Proxy>> {
208        self.client.put("/v1/proxies", &update).await
209    }
210
211    /// Update specific proxy - PUT /v1/proxies/{uid}
212    pub async fn update(&self, uid: u32, update: ProxyUpdate) -> Result<Proxy> {
213        self.client
214            .put(&format!("/v1/proxies/{}", uid), &update)
215            .await
216    }
217}
218
219/// Proxy update body
220#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct ProxyUpdate {
222    #[serde(skip_serializing_if = "Option::is_none")]
223    pub max_connections: Option<u32>,
224    #[serde(skip_serializing_if = "Option::is_none")]
225    pub threads: Option<u32>,
226    #[serde(flatten)]
227    pub extra: Value,
228}