// Sentinel routing. Redis Sentinel monitors masters and promotes a replica on failure; a
// client asks a sentinel for the current master address rather than hard-coding it. These
// are the resolution pieces, tested against fakes; the resolved `host:port` is then dialed
// as an ordinary client (see the socket package).
///|
/// `SENTINEL ...`: send a raw sentinel sub-command (the sub-command name is the first
/// `args` element), returning the reply.
pub async fn Client::sentinel(
self : Client,
args : Array[String],
) -> @resp.RespValue raise RedisError {
let cmd : Array[Bytes] = [b"SENTINEL"]
for a in args {
cmd.push(arg_string(a))
}
self.command(cmd)
}
///|
/// `SENTINEL GET-MASTER-ADDR-BY-NAME name`: the current master's `(host, port)` for the
/// monitored master `name`, or `None` if the sentinel does not know it.
pub async fn Client::sentinel_get_master_addr_by_name(
self : Client,
name : String,
) -> (String, Int32)? raise RedisError {
let reply = self.command([
b"SENTINEL",
b"GET-MASTER-ADDR-BY-NAME",
arg_string(name),
])
match reply {
@resp.Array(items) => {
guard items.length() >= 2 else { return None }
let host = @utf8.decode_lossy(expect_bytes(items[0]).unwrap())
let port = expect_number(items[1]).to_int()
Some((host, port))
}
_ => None
}
}
///|
/// A client that resolves a master address through a list of sentinel connections, trying
/// each in turn until one answers.
pub struct SentinelClient {
sentinels : Array[&RedisConn]
}
///|
/// A sentinel client over `sentinels` (connection to each sentinel node).
pub fn SentinelClient::new(sentinels : Array[&RedisConn]) -> SentinelClient {
{ sentinels, }
}
///|
/// Resolve the master address for `name`, querying sentinels in order; the first answer
/// wins. Returns the `host:port` string to dial.
pub async fn SentinelClient::resolve(
self : SentinelClient,
name : String,
) -> String raise RedisError {
for s in self.sentinels {
let client = Client::new(s)
match client.sentinel_get_master_addr_by_name(name) {
Some((host, port)) => return host + ":" + port.to_string()
None => ()
}
}
raise Connection("no sentinel resolved master for " + name)
}