diff --git a/explorer-api/src/ping/http.rs b/explorer-api/src/ping/http.rs index 962529d779..248db7874d 100644 --- a/explorer-api/src/ping/http.rs +++ b/explorer-api/src/ping/http.rs @@ -25,6 +25,7 @@ pub(crate) async fn index( Some(cache_value) => { trace!("Returning cached value for {}", pubkey); Some(Json(PingResponse { + pending: cache_value.pending, ports: cache_value.ports, })) } @@ -33,11 +34,16 @@ pub(crate) async fn index( match state.inner.get_mix_node(pubkey).await { Some(bond) => { - let ports = port_check(&bond).await; + // set status to pending, so that any HTTP requests are pending + state.inner.ping_cache.set_pending(pubkey).await; + // do the check + let ports = Some(port_check(&bond).await); trace!("Tested mix node {}: {:?}", pubkey, ports); - - let response = PingResponse { ports }; + let response = PingResponse { + ports, + pending: false, + }; // cache for 1 min trace!("Caching value for {}", pubkey); diff --git a/explorer-api/src/ping/models.rs b/explorer-api/src/ping/models.rs index 1316452448..28588d550f 100644 --- a/explorer-api/src/ping/models.rs +++ b/explorer-api/src/ping/models.rs @@ -8,7 +8,8 @@ use tokio::sync::RwLock; pub(crate) type PingCache = HashMap; -const CACHE_TTL: Duration = Duration::from_secs(60 * 60); // 1 hour +const PING_TTL: Duration = Duration::from_secs(60 * 5); // 5 mins, before port check will be re-tried (only while pending) +const CACHE_TTL: Duration = Duration::from_secs(60 * 60); // 1 hour, to cache result from port check #[derive(Clone)] pub(crate) struct ThreadsafePingCache { @@ -28,15 +29,36 @@ impl ThreadsafePingCache { .await .get(identity_key) .filter(|cache_item| cache_item.valid_until > SystemTime::now()) - .map(|cache_item| PingResponse { - ports: cache_item.ports.clone(), + .map(|cache_item| { + if cache_item.pending { + return PingResponse { + pending: true, + ports: None, + }; + } + PingResponse { + pending: false, + ports: cache_item.ports.clone(), + } }) } + pub(crate) async fn set_pending(&self, identity_key: &str) { + self.inner.write().await.insert( + identity_key.to_string(), + PingCacheItem { + pending: true, + valid_until: SystemTime::now() + PING_TTL, + ports: None, + }, + ); + } + pub(crate) async fn set(&self, identity_key: &str, item: PingResponse) { self.inner.write().await.insert( identity_key.to_string(), PingCacheItem { + pending: false, valid_until: SystemTime::now() + CACHE_TTL, ports: item.ports, }, @@ -46,10 +68,12 @@ impl ThreadsafePingCache { #[derive(Deserialize, Serialize, JsonSchema, Clone)] pub(crate) struct PingResponse { - pub(crate) ports: HashMap, + pub(crate) pending: bool, + pub(crate) ports: Option>, } pub(crate) struct PingCacheItem { - pub(crate) ports: HashMap, + pub(crate) pending: bool, + pub(crate) ports: Option>, pub(crate) valid_until: std::time::SystemTime, }