Skip to content

Commit 408fd5b

Browse files
lutterclaude
andcommitted
graph, store: Add time-based connection validation to skip health checks for active connections
Connections that were used within the last 30 seconds (configurable via GRAPH_STORE_CONNECTION_VALIDATION_IDLE_SECS) now skip the SELECT 67 health check during pool recycle. This reduces connection checkout latency from ~4ms to ~0ms for frequently-used connections while still validating idle connections to detect stale database connections. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent a4cb593 commit 408fd5b

File tree

3 files changed

+23
-1
lines changed

3 files changed

+23
-1
lines changed

graph/src/env/store.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ pub struct EnvVarsStore {
166166
/// Set by `GRAPH_STORE_DISABLE_CHAIN_HEAD_PTR_CACHE`. Default is false.
167167
/// Set to true to disable chain_head_ptr caching (safety escape hatch).
168168
pub disable_chain_head_ptr_cache: bool,
169+
/// Minimum idle time before running connection health check (SELECT 67).
170+
/// Connections used more recently than this threshold skip validation.
171+
/// Set to 0 to always validate (previous behavior).
172+
/// Set by `GRAPH_STORE_CONNECTION_VALIDATION_IDLE_SECS`. Default is 30 seconds.
173+
pub connection_validation_idle_secs: Duration,
169174
}
170175

171176
// This does not print any values avoid accidentally leaking any sensitive env vars
@@ -228,6 +233,7 @@ impl TryFrom<InnerStore> for EnvVarsStore {
228233
account_like_max_unique_ratio: x.account_like_max_unique_ratio.map(|r| r.0),
229234
disable_call_cache: x.disable_call_cache,
230235
disable_chain_head_ptr_cache: x.disable_chain_head_ptr_cache,
236+
connection_validation_idle_secs: Duration::from_secs(x.connection_validation_idle_secs),
231237
};
232238
if let Some(timeout) = vars.batch_timeout {
233239
if timeout < 2 * vars.batch_target_duration {
@@ -337,6 +343,8 @@ pub struct InnerStore {
337343
disable_call_cache: bool,
338344
#[envconfig(from = "GRAPH_STORE_DISABLE_CHAIN_HEAD_PTR_CACHE", default = "false")]
339345
disable_chain_head_ptr_cache: bool,
346+
#[envconfig(from = "GRAPH_STORE_CONNECTION_VALIDATION_IDLE_SECS", default = "30")]
347+
connection_validation_idle_secs: u64,
340348
}
341349

342350
#[derive(Clone, Copy, Debug)]

store/postgres/src/pool/manager.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ pub struct ConnectionManager {
3535
connection_url: String,
3636
state_tracker: StateTracker,
3737
error_counter: Counter,
38+
/// Connections idle for less than this threshold skip the SELECT 67 health check
39+
validation_idle_threshold: Duration,
3840
}
3941

4042
impl ConnectionManager {
@@ -44,6 +46,7 @@ impl ConnectionManager {
4446
state_tracker: StateTracker,
4547
registry: &MetricsRegistry,
4648
const_labels: HashMap<String, String>,
49+
validation_idle_threshold: Duration,
4750
) -> Self {
4851
let error_counter = registry
4952
.global_counter(
@@ -58,6 +61,7 @@ impl ConnectionManager {
5861
connection_url,
5962
state_tracker,
6063
error_counter,
64+
validation_idle_threshold,
6165
}
6266
}
6367

@@ -105,11 +109,20 @@ impl deadpool::managed::Manager for ConnectionManager {
105109
async fn recycle(
106110
&self,
107111
obj: &mut Self::Type,
108-
_metrics: &deadpool::managed::Metrics,
112+
metrics: &deadpool::managed::Metrics,
109113
) -> RecycleResult<Self::Error> {
110114
if std::thread::panicking() || obj.is_broken() {
111115
return Err(RecycleError::Message("Broken connection".into()));
112116
}
117+
118+
// Skip health check if connection was used recently
119+
if self.validation_idle_threshold > Duration::ZERO
120+
&& metrics.last_used() < self.validation_idle_threshold
121+
{
122+
return Ok(());
123+
}
124+
125+
// Run SELECT 67 only for idle connections
113126
let res = diesel::select(67_i32.into_sql::<diesel::sql_types::Integer>())
114127
.execute(obj)
115128
.await

store/postgres/src/pool/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ impl PoolInner {
476476
state_tracker.clone(),
477477
&registry,
478478
const_labels.clone(),
479+
ENV_VARS.store.connection_validation_idle_secs,
479480
);
480481

481482
let timeouts = Timeouts {

0 commit comments

Comments
 (0)