Skip to content
This repository was archived by the owner on Aug 9, 2022. It is now read-only.

Commit ea82501

Browse files
authored
fix: fix blocking timeout and add more related config (#61)
* fix: fix blocking timeout and more related config; decrease lock time for health check * fix test * fmt
1 parent 23569a1 commit ea82501

File tree

6 files changed

+55
-23
lines changed

6 files changed

+55
-23
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/config-template.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
[ws]
22
# Elara kv websocket service address
33
addr = "127.0.0.1:9002"
4+
# default to 10
5+
heartbeat_interval_sec = 10
46

57
[client]
8+
# response timeout
9+
# default to 3000
10+
timeout_ms = 3000
611
max_request_cap = 256
712
max_cap_per_subscription = 64
813

914
# polkadot config
1015
[nodes.polkadot]
1116
url = "wss://rpc.polkadot.io"
1217
# kusama config
13-
#[nodes.kusama]
14-
#url = "wss://kusama-rpc.polkadot.io"
18+
[nodes.kusama]
19+
url = "wss://kusama-rpc.polkadot.io"

bin/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ async fn main() -> Result<()> {
1111
let opt = CliOpts::init();
1212
let toml = fs::read_to_string(opt.config.as_path())?;
1313
let config = ServiceConfig::parse(toml)?;
14-
log::debug!("Load config: {:#?}", config);
14+
log::info!("Load config: {:#?}", config);
1515

1616
start_server(config).await
1717
}

src/config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct ServiceInnerConfig {
4343
#[derive(Clone, Debug, Serialize, Deserialize)]
4444
pub struct WsConfig {
4545
pub addr: String,
46+
pub heartbeat_interval_sec: Option<u64>,
4647
}
4748

4849
#[derive(Clone, Debug, Serialize, Deserialize)]
@@ -52,6 +53,7 @@ pub struct NodeConfig {
5253

5354
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
5455
pub struct RpcClientConfig {
56+
pub timeout_ms: Option<u64>,
5557
pub max_request_cap: Option<usize>,
5658
pub max_cap_per_subscription: Option<usize>,
5759
}
@@ -74,6 +76,7 @@ fn test_toml_config() {
7476
let config = ServiceInnerConfig {
7577
ws: WsConfig {
7678
addr: "localhost:9002".into(),
79+
heartbeat_interval_sec: Some(10),
7780
},
7881
nodes,
7982
client: None,

src/lib.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ impl From<&str> for Chain {
5353
}
5454
}
5555

56-
const CONN_EXPIRED_TIME_SECS: u64 = 10;
57-
const CHECK_CONN_ALIVE_SECS: u64 = 10;
56+
const CONN_EXPIRED_TIME_SEC: u64 = 10;
57+
const HEARTBEAT_INTERVAL_SEC: u64 = 10;
5858

5959
pub async fn start_server(config: ServiceConfig) -> Result<()> {
6060
let server = WsServer::bind(config.ws.addr.as_str()).await?;
@@ -103,7 +103,7 @@ async fn remove_expired_connections(mut conns: WsConnections) {
103103
log::info!("Total connection num: {}", conns.len().await);
104104
}
105105

106-
tokio::time::sleep(Duration::from_secs(CONN_EXPIRED_TIME_SECS)).await;
106+
tokio::time::sleep(Duration::from_secs(CONN_EXPIRED_TIME_SEC)).await;
107107
}
108108
}
109109

@@ -117,7 +117,8 @@ async fn create_clients(
117117
let mut client = RpcClient::new(chain.clone(), node.url.clone(), config.client).await?;
118118
subscribe_chain(connections.clone(), &mut client).await;
119119
let client = Arc::new(RwLock::new(client));
120-
tokio::spawn(health_check(connections.clone(), client.clone()));
120+
let config = config.clone();
121+
tokio::spawn(health_check(connections.clone(), client.clone(), config));
121122
// maintains these clients
122123
clients.insert(chain.clone(), client);
123124
}
@@ -126,14 +127,28 @@ async fn create_clients(
126127
}
127128

128129
// if rpc client is not alive, we reconnect to peer
129-
async fn health_check(connections: WsConnections, client: ArcRpcClient) {
130+
async fn health_check(connections: WsConnections, client: ArcRpcClient, config: ServiceConfig) {
130131
loop {
131-
tokio::time::sleep(Duration::from_secs(CHECK_CONN_ALIVE_SECS)).await;
132+
tokio::time::sleep(Duration::from_secs(
133+
config
134+
.ws
135+
.heartbeat_interval_sec
136+
.unwrap_or(HEARTBEAT_INTERVAL_SEC),
137+
))
138+
.await;
139+
let mut is_alive = true;
140+
// use read lock.
141+
{
142+
let client = client.read().await;
143+
if !client.is_alive().await {
144+
is_alive = false;
145+
}
146+
}
132147

133-
let mut client = client.write().await;
134-
if !client.is_alive().await {
148+
if !is_alive {
149+
let mut client = client.write().await;
135150
log::info!(
136-
"Trying to reconnect to `{}` to `{}`...",
151+
"Trying to reconnect to `{}`/`{}`...",
137152
client.chain(),
138153
client.addr()
139154
);

src/rpc_client.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{
1515
substrate::constants::{state_getRuntimeVersion, system_health},
1616
Chain,
1717
};
18+
use tokio::time::Duration;
1819

1920
pub type Result<T, E = WsClientError> = std::result::Result<T, E>;
2021
pub type NotificationStream = WsSubscription<SubscriptionNotification>;
@@ -25,6 +26,7 @@ pub struct RpcClient {
2526
ws: WsClient,
2627
chain: Chain,
2728
addr: String,
29+
config: Option<RpcClientConfig>,
2830
// TODO: use arc for splitting lifetime
2931
pub ctx: Option<RpcClientCtx>,
3032
}
@@ -40,26 +42,33 @@ pub type ArcRpcClient = Arc<RwLock<RpcClient>>;
4042
pub type RpcClients = HashMap<Chain, ArcRpcClient>;
4143

4244
impl RpcClient {
43-
pub async fn new(
44-
chain: Chain,
45-
addr: impl Into<String>,
46-
config: Option<RpcClientConfig>,
47-
) -> Result<Self> {
48-
let addr = addr.into();
45+
async fn create_ws_client(addr: &str, config: Option<RpcClientConfig>) -> Result<WsClient> {
4946
let ws = if let Some(config) = config {
5047
WsClient::builder()
48+
.timeout(Duration::from_millis(config.timeout_ms.unwrap_or(3000)))
5149
.max_concurrent_request_capacity(config.max_request_cap.unwrap_or(256))
5250
.max_capacity_per_subscription(config.max_cap_per_subscription.unwrap_or(64))
53-
.build(addr.as_str())
51+
.build(addr)
5452
.await?
5553
} else {
56-
WsClient::new(addr.as_str()).await?
54+
WsClient::new(addr).await?
5755
};
56+
Ok(ws)
57+
}
58+
59+
pub async fn new(
60+
chain: Chain,
61+
addr: impl Into<String>,
62+
config: Option<RpcClientConfig>,
63+
) -> Result<Self> {
64+
let addr = addr.into();
65+
let ws = Self::create_ws_client(addr.as_str(), config).await?;
5866

5967
Ok(Self {
6068
chain,
6169
ws,
6270
addr,
71+
config,
6372
ctx: Default::default(),
6473
})
6574
}
@@ -114,7 +123,7 @@ impl RpcClient {
114123

115124
// After `reconnect`ed, client need to re`subscribe`.
116125
pub async fn reconnect(&mut self) -> Result<()> {
117-
self.ws = WsClient::new(self.addr.as_str()).await?;
126+
self.ws = Self::create_ws_client(self.addr.as_str(), self.config).await?;
118127
Ok(())
119128
}
120129

0 commit comments

Comments
 (0)