risingwave_common/util/
addr.rs1use std::net::{SocketAddr, ToSocketAddrs};
16use std::str::FromStr;
17use std::time::Duration;
18
19use anyhow::Context;
20use risingwave_pb::common::PbHostAddress;
21use thiserror_ext::AsReport;
22use tokio::time::sleep;
23use tracing::error;
24
25use crate::util::retry::exponential_backoff;
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash)]
29pub struct HostAddr {
30 pub host: String,
31 pub port: u16,
32}
33
34impl std::fmt::Display for HostAddr {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 write!(f, "{}:{}", self.host, self.port)
37 }
38}
39impl From<SocketAddr> for HostAddr {
40 fn from(addr: SocketAddr) -> Self {
41 HostAddr {
42 host: addr.ip().to_string(),
43 port: addr.port(),
44 }
45 }
46}
47
48impl TryFrom<&str> for HostAddr {
49 type Error = anyhow::Error;
50
51 fn try_from(s: &str) -> Result<Self, Self::Error> {
52 let s = format!("http://{s}");
53 let addr = url::Url::parse(&s).with_context(|| format!("failed to parse address: {s}"))?;
54 Ok(HostAddr {
55 host: addr.host().context("invalid host")?.to_string(),
56 port: addr.port().context("invalid port")?,
57 })
58 }
59}
60
61impl TryFrom<&String> for HostAddr {
62 type Error = anyhow::Error;
63
64 fn try_from(s: &String) -> Result<Self, Self::Error> {
65 Self::try_from(s.as_str())
66 }
67}
68
69impl FromStr for HostAddr {
70 type Err = anyhow::Error;
71
72 fn from_str(s: &str) -> Result<Self, Self::Err> {
73 Self::try_from(s)
74 }
75}
76
77impl From<&PbHostAddress> for HostAddr {
78 fn from(addr: &PbHostAddress) -> Self {
79 HostAddr {
80 host: addr.get_host().clone(),
81 port: addr.get_port() as u16,
82 }
83 }
84}
85
86impl HostAddr {
87 pub fn to_protobuf(&self) -> PbHostAddress {
88 PbHostAddress {
89 host: self.host.clone(),
90 port: self.port as i32,
91 }
92 }
93}
94
95pub fn is_local_address(server_addr: &HostAddr, peer_addr: &HostAddr) -> bool {
96 server_addr == peer_addr
97}
98
99pub async fn try_resolve_dns(host: &str, port: i32) -> Result<SocketAddr, String> {
100 let addr = format!("{}:{}", host, port);
101 let mut backoff = exponential_backoff(Duration::from_millis(100), 5, Duration::from_secs(3));
102 const MAX_RETRY: usize = 20;
103 for i in 1..=MAX_RETRY {
104 let err = match addr.to_socket_addrs() {
105 Ok(mut addr_iter) => {
106 if let Some(addr) = addr_iter.next() {
107 return Ok(addr);
108 } else {
109 format!("{} resolved to no addr", addr)
110 }
111 }
112 Err(e) => e.to_report_string(),
113 };
114 let delay = backoff.next().unwrap();
117 error!(
118 attempt = i,
119 backoff_delay = ?delay,
120 err,
121 addr,
122 "failed to resolve the worker node address",
123 );
124 sleep(delay).await;
125 }
126 Err(format!("failed to resolve dns: {}", addr))
127}
128
129#[cfg(test)]
130mod tests {
131 use crate::util::addr::{HostAddr, is_local_address};
132
133 #[test]
134 fn test_is_local_address() {
135 let check_local = |a: &str, b: &str, result: bool| {
136 assert_eq!(
137 is_local_address(&a.parse().unwrap(), &b.parse().unwrap()),
138 result
139 );
140 };
141 check_local("localhost:3456", "localhost:3456", true);
142 check_local("10.11.12.13:3456", "10.11.12.13:3456", true);
143 check_local("some.host.in.k8s:3456", "some.host.in.k8s:3456", true);
144 check_local("some.host.in.k8s:3456", "other.host.in.k8s:3456", false);
145 check_local("some.host.in.k8s:3456", "some.host.in.k8s:4567", false);
146 }
147
148 #[test]
149 fn test_host_addr_convert() {
150 let addr = "1.2.3.4:567";
151 assert_eq!(
152 addr.parse::<HostAddr>().unwrap(),
153 HostAddr {
154 host: String::from("1.2.3.4"),
155 port: 567
156 }
157 );
158 let addr = "test.test:12345";
159 assert_eq!(
160 addr.parse::<HostAddr>().unwrap(),
161 HostAddr {
162 host: String::from("test.test"),
163 port: 12345
164 }
165 );
166 let addr = "test.test";
167 assert!(addr.parse::<HostAddr>().is_err());
168 let addr = "test.test:65537";
169 assert!(addr.parse::<HostAddr>().is_err());
170 let addr = "test.test:";
171 assert!(addr.parse::<HostAddr>().is_err());
172 let addr = "test.test:12345:12345";
173 assert!(addr.parse::<HostAddr>().is_err());
174 }
175}