rustis/commands/
sentinel_commands.rs

1use crate::{
2    client::{prepare_command, PreparedCommand},
3    resp::{
4        cmd, CommandArgs, KeyValueArgsCollection, KeyValueCollectionResponse,
5        MultipleArgsCollection, PrimitiveResponse, SingleArg, ToArgs, Value,
6    },
7};
8use serde::Deserialize;
9
10/// A group of Redis commands related to [Sentinel](https://redis.io/docs/management/sentinel/)
11/// # See Also
12/// [Sentinel Commands](https://redis.io/docs/management/sentinel/#sentinel-commands)
13pub trait SentinelCommands<'a> {
14    /// Get the current value of a global Sentinel configuration parameter.
15    ///
16    /// The specified name may be a wildcard.
17    /// Similar to the Redis [`config_get`](crate::commands::ServerCommands::config_get) command.
18    #[must_use]
19    fn sentinel_config_get<N, RN, RV, R>(self, name: N) -> PreparedCommand<'a, Self, R>
20    where
21        Self: Sized,
22        N: SingleArg,
23        RN: PrimitiveResponse,
24        RV: PrimitiveResponse,
25        R: KeyValueCollectionResponse<RN, RV>,
26    {
27        prepare_command(self, cmd("SENTINEL").arg("CONFIG").arg("GET").arg(name))
28    }
29
30    /// Set the value of a global Sentinel configuration parameter.
31    #[must_use]
32    fn sentinel_config_set<N, V>(self, name: N, value: V) -> PreparedCommand<'a, Self, ()>
33    where
34        Self: Sized,
35        N: SingleArg,
36        V: SingleArg,
37    {
38        prepare_command(
39            self,
40            cmd("SENTINEL")
41                .arg("CONFIG")
42                .arg("SET")
43                .arg(name)
44                .arg(value),
45        )
46    }
47
48    /// Check if the current Sentinel configuration is able to reach the quorum needed to failover a master,
49    /// and the majority needed to authorize the failover.
50    ///
51    /// This command should be used in monitoring systems to check if a Sentinel deployment is ok.
52    #[must_use]
53    fn sentinel_ckquorum<N>(self, master_name: N) -> PreparedCommand<'a, Self, ()>
54    where
55        Self: Sized,
56        N: SingleArg,
57    {
58        prepare_command(self, cmd("SENTINEL").arg("CKQUORUM").arg(master_name))
59    }
60
61    /// Force a failover as if the master was not reachable,
62    /// and without asking for agreement to other Sentinels
63    /// (however a new version of the configuration will be published
64    /// so that the other Sentinels will update their configurations).
65    #[must_use]
66    fn sentinel_failover<N>(self, master_name: N) -> PreparedCommand<'a, Self, ()>
67    where
68        Self: Sized,
69        N: SingleArg,
70    {
71        prepare_command(self, cmd("SENTINEL").arg("FAILOVER").arg(master_name))
72    }
73
74    /// Force Sentinel to rewrite its configuration on disk, including the current Sentinel state.
75    ///
76    /// Normally Sentinel rewrites the configuration every time something changes in its state
77    /// (in the context of the subset of the state which is persisted on disk across restart).
78    ///  However sometimes it is possible that the configuration file is lost because of operation errors,
79    /// disk failures, package upgrade scripts or configuration managers.
80    /// In those cases a way to force Sentinel to rewrite the configuration file is handy.
81    /// This command works even if the previous configuration file is completely missing.
82    #[must_use]
83    fn sentinel_flushconfig(self) -> PreparedCommand<'a, Self, ()>
84    where
85        Self: Sized,
86    {
87        prepare_command(self, cmd("SENTINEL").arg("FLUSHCONFIG"))
88    }
89
90    /// Return the ip and port number of the master with that name.
91    ///
92    /// If a failover is in progress or terminated successfully for this master,
93    /// it returns the address and port of the promoted replica.
94    ///
95    /// # Return
96    /// * `None` if sentinel does not know this master
97    /// * A tuple made up of
98    ///     * The IP of the master
99    ///     * The port of the master
100    #[must_use]
101    fn sentinel_get_master_addr_by_name<N>(
102        self,
103        master_name: N,
104    ) -> PreparedCommand<'a, Self, Option<(String, u16)>>
105    where
106        Self: Sized,
107        N: SingleArg,
108    {
109        prepare_command(
110            self,
111            cmd("SENTINEL")
112                .arg("GET-MASTER-ADDR-BY-NAME")
113                .arg(master_name),
114        )
115    }
116
117    /// Return cached [`info`](crate::commands::ServerCommands::info) output from masters and replicas.
118    #[must_use]
119    fn sentinel_info_cache<N, NN, R>(self, master_names: NN) -> PreparedCommand<'a, Self, R>
120    where
121        Self: Sized,
122        N: SingleArg,
123        NN: MultipleArgsCollection<N>,
124        R: KeyValueCollectionResponse<String, Vec<(u64, String)>>,
125    {
126        prepare_command(self, cmd("SENTINEL").arg("INFO-CACHE").arg(master_names))
127    }
128
129    /// Show the state and info of the specified master.
130    #[must_use]
131    fn sentinel_master<N>(self, master_name: N) -> PreparedCommand<'a, Self, SentinelMasterInfo>
132    where
133        Self: Sized,
134        N: SingleArg,
135    {
136        prepare_command(self, cmd("SENTINEL").arg("MASTER").arg(master_name))
137    }
138
139    /// Show a list of monitored masters and their state.
140    #[must_use]
141    fn sentinel_masters(self) -> PreparedCommand<'a, Self, Vec<SentinelMasterInfo>>
142    where
143        Self: Sized,
144    {
145        prepare_command(self, cmd("SENTINEL").arg("MASTERS"))
146    }
147
148    /// This command tells the Sentinel to start monitoring a new master
149    /// with the specified name, ip, port, and quorum.
150    ///
151    /// It is identical to the sentinel monitor configuration directive in `sentinel.conf` configuration file,
152    /// with the difference that you can't use a hostname in as ip,
153    /// but you need to provide an IPv4 or IPv6 address.
154    #[must_use]
155    fn sentinel_monitor<N, I>(
156        self,
157        name: N,
158        ip: I,
159        port: u16,
160        quorum: usize,
161    ) -> PreparedCommand<'a, Self, ()>
162    where
163        Self: Sized,
164        N: SingleArg,
165        I: SingleArg,
166    {
167        prepare_command(
168            self,
169            cmd("SENTINEL")
170                .arg("MONITOR")
171                .arg(name)
172                .arg(ip)
173                .arg(port)
174                .arg(quorum),
175        )
176    }
177
178    /// This command is used in order to remove the specified master.
179    ///
180    /// The master will no longer be monitored,
181    /// and will totally be removed from the internal state of the Sentinel,
182    /// so it will no longer listed by [`sentinel_masters`](SentinelCommands::sentinel_masters) and so forth.
183    #[must_use]
184    fn sentinel_remove<N>(self, name: N) -> PreparedCommand<'a, Self, ()>
185    where
186        Self: Sized,
187        N: SingleArg,
188    {
189        prepare_command(self, cmd("SENTINEL").arg("REMOVE").arg(name))
190    }
191
192    /// The SET command is very similar to the [`config_set`](crate::commands::ServerCommands::config_set) command of Redis,
193    /// and is used in order to change configuration parameters of a specific master.
194    ///
195    /// Multiple option / value pairs can be specified (or none at all).
196    /// All the configuration parameters that can be configured via `sentinel.conf`
197    /// are also configurable using this command.
198    #[must_use]
199    fn sentinel_set<N, O, V, C>(self, name: N, configs: C) -> PreparedCommand<'a, Self, ()>
200    where
201        Self: Sized,
202        N: SingleArg,
203        O: SingleArg,
204        V: SingleArg,
205        C: KeyValueArgsCollection<O, V>,
206    {
207        prepare_command(self, cmd("SENTINEL").arg("SET").arg(name).arg(configs))
208    }
209
210    /// Return the ID of the Sentinel instance.
211    #[must_use]
212    fn sentinel_myid(self) -> PreparedCommand<'a, Self, String>
213    where
214        Self: Sized,
215    {
216        prepare_command(self, cmd("SENTINEL").arg("MYID"))
217    }
218
219    /// This command returns information about pending scripts.
220    #[must_use]
221    fn sentinel_pending_scripts(self) -> PreparedCommand<'a, Self, Vec<Value>>
222    where
223        Self: Sized,
224    {
225        prepare_command(self, cmd("SENTINEL").arg("PENDING-SCRIPTS"))
226    }
227
228    /// Show a list of replicas for this master, and their state.
229    #[must_use]
230    fn sentinel_replicas<N>(
231        self,
232        master_name: N,
233    ) -> PreparedCommand<'a, Self, Vec<SentinelReplicaInfo>>
234    where
235        Self: Sized,
236        N: SingleArg,
237    {
238        prepare_command(self, cmd("SENTINEL").arg("REPLICAS").arg(master_name))
239    }
240
241    /// This command will reset all the masters with matching name.
242    ///
243    /// The pattern argument is a glob-style pattern.
244    /// The reset process clears any previous state in a master (including a failover in progress),
245    /// and removes every replica and sentinel already discovered and associated with the master.
246    ///
247    /// # Return
248    /// The number of reset masters
249    #[must_use]
250    fn sentinel_reset<P>(self, pattern: P) -> PreparedCommand<'a, Self, usize>
251    where
252        Self: Sized,
253        P: SingleArg,
254    {
255        prepare_command(self, cmd("SENTINEL").arg("RESET").arg(pattern))
256    }
257
258    ///  Show a list of sentinel instances for this master, and their state.
259    #[must_use]
260    fn sentinel_sentinels<N>(self, master_name: N) -> PreparedCommand<'a, Self, Vec<SentinelInfo>>
261    where
262        Self: Sized,
263        N: SingleArg,
264    {
265        prepare_command(self, cmd("SENTINEL").arg("SENTINELS").arg(master_name))
266    }
267
268    ///  This command simulates different Sentinel crash scenarios.
269    #[must_use]
270    fn sentinel_simulate_failure(
271        self,
272        mode: SentinelSimulateFailureMode,
273    ) -> PreparedCommand<'a, Self, ()>
274    where
275        Self: Sized,
276    {
277        prepare_command(self, cmd("SENTINEL").arg("SIMULATE-FAILURE").arg(mode))
278    }
279}
280
281/// Result for the [`sentinel_master`](SentinelCommands::sentinel_master) command.
282#[derive(Debug, Deserialize)]
283#[serde(rename_all = "kebab-case")]
284pub struct SentinelMasterInfo {
285    pub name: String,
286    pub ip: String,
287    pub port: u16,
288    pub runid: String,
289    pub flags: String,
290    pub link_pending_commands: usize,
291    pub link_refcount: usize,
292    pub last_ping_sent: usize,
293    pub last_ok_ping_reply: usize,
294    pub last_ping_reply: usize,
295    pub down_after_milliseconds: u64,
296    pub info_refresh: u64,
297    pub role_reported: String,
298    pub role_reported_time: u64,
299    pub config_epoch: usize,
300    pub num_slaves: usize,
301    pub num_other_sentinels: usize,
302    pub quorum: usize,
303    pub failover_timeout: u64,
304    pub parallel_syncs: usize,
305}
306
307/// /// Result for the [`sentinel_replicas`](SentinelCommands::sentinel_replicas) command.
308#[derive(Debug, Deserialize)]
309#[serde(rename_all = "kebab-case")]
310pub struct SentinelReplicaInfo {
311    pub name: String,
312    pub ip: String,
313    pub port: u16,
314    pub runid: String,
315    pub flags: String,
316    pub link_pending_commands: usize,
317    pub link_refcount: usize,
318    pub last_ping_sent: usize,
319    pub last_ok_ping_reply: usize,
320    pub last_ping_reply: usize,
321    pub down_after_milliseconds: u64,
322    pub info_refresh: u64,
323    pub role_reported: String,
324    pub role_reported_time: u64,
325    pub master_link_down_time: u64,
326    pub master_link_status: String,
327    pub master_host: String,
328    pub master_port: u16,
329    pub slave_priority: u64,
330    pub slave_repl_offset: u64,
331    pub replica_announced: usize,
332}
333
334/// Result for the [`sentinel_sentinels`](SentinelCommands::sentinel_sentinels) command.
335#[derive(Deserialize)]
336#[serde(rename_all = "kebab-case")]
337pub struct SentinelInfo {
338    pub name: String,
339    pub ip: String,
340    pub port: u16,
341    pub runid: String,
342    pub flags: String,
343    pub link_pending_commands: usize,
344    pub link_refcount: usize,
345    pub last_ping_sent: usize,
346    pub last_ok_ping_reply: usize,
347    pub last_ping_reply: usize,
348    pub down_after_milliseconds: u64,
349    pub last_hello_message: u64,
350    pub voted_leader: String,
351    pub voted_leader_epoch: usize,
352}
353
354/// Different crash simulation scenario modes for
355/// the [`sentinel_simulate_failure`](SentinelCommands::sentinel_simulate_failure) command
356pub enum SentinelSimulateFailureMode {
357    CrashAfterElection,
358    CrashAfterPromotion,
359}
360
361impl ToArgs for SentinelSimulateFailureMode {
362    fn write_args(&self, args: &mut CommandArgs) {
363        args.arg(match self {
364            SentinelSimulateFailureMode::CrashAfterElection => "CRASH-AFTER-ELECTION",
365            SentinelSimulateFailureMode::CrashAfterPromotion => "CRASH-AFTER-PROMOTION",
366        });
367    }
368}