Skip to content

Commit 81c848b

Browse files
committed
add metric to measure how long it takes to obtain a db connection
1 parent 04a7a2c commit 81c848b

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

src/app.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ impl App {
6262
pub fn new(config: config::Server, http_client: Option<Client>) -> App {
6363
use oauth2::{AuthUrl, ClientId, ClientSecret, TokenUrl};
6464

65+
let instance_metrics =
66+
InstanceMetrics::new().expect("could not initialize instance metrics");
67+
6568
let github = GitHubClient::new(http_client.clone(), config.gh_base_url.clone());
6669

6770
let github_oauth = BasicClient::new(
@@ -116,7 +119,14 @@ impl App {
116119
.connection_customizer(Box::new(primary_db_connection_config))
117120
.thread_pool(thread_pool.clone());
118121

119-
DieselPool::new(&config.db.primary.url, primary_db_config).unwrap()
122+
DieselPool::new(
123+
&config.db.primary.url,
124+
primary_db_config,
125+
instance_metrics
126+
.database_time_to_obtain_connection
127+
.with_label_values(&["primary"]),
128+
)
129+
.unwrap()
120130
};
121131

122132
let replica_database = if let Some(url) = config.db.replica.as_ref().map(|c| &c.url) {
@@ -135,7 +145,16 @@ impl App {
135145
.connection_customizer(Box::new(replica_db_connection_config))
136146
.thread_pool(thread_pool);
137147

138-
Some(DieselPool::new(url, replica_db_config).unwrap())
148+
Some(
149+
DieselPool::new(
150+
url,
151+
replica_db_config,
152+
instance_metrics
153+
.database_time_to_obtain_connection
154+
.with_label_values(&["follower"]),
155+
)
156+
.unwrap(),
157+
)
139158
}
140159
} else {
141160
None
@@ -150,8 +169,7 @@ impl App {
150169
downloads_counter: DownloadsCounter::new(),
151170
emails: Emails::from_environment(),
152171
service_metrics: ServiceMetrics::new().expect("could not initialize service metrics"),
153-
instance_metrics: InstanceMetrics::new()
154-
.expect("could not initialize instance metrics"),
172+
instance_metrics,
155173
http_client,
156174
}
157175
}

src/db.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use conduit::RequestExt;
22
use diesel::prelude::*;
33
use diesel::r2d2::{self, ConnectionManager, CustomizeConnection};
44
use parking_lot::{ReentrantMutex, ReentrantMutexGuard};
5+
use prometheus::Histogram;
56
use std::sync::Arc;
67
use std::{ops::Deref, time::Duration};
78
use url::Url;
@@ -10,14 +11,18 @@ use crate::middleware::app::RequestApp;
1011

1112
#[derive(Clone)]
1213
pub enum DieselPool {
13-
Pool(r2d2::Pool<ConnectionManager<PgConnection>>),
14+
Pool {
15+
pool: r2d2::Pool<ConnectionManager<PgConnection>>,
16+
time_to_obtain_connection_metric: Histogram,
17+
},
1418
Test(Arc<ReentrantMutex<PgConnection>>),
1519
}
1620

1721
impl DieselPool {
1822
pub(crate) fn new(
1923
url: &str,
2024
config: r2d2::Builder<ConnectionManager<PgConnection>>,
25+
time_to_obtain_connection_metric: Histogram,
2126
) -> Result<DieselPool, PoolError> {
2227
let manager = ConnectionManager::new(connection_url(url));
2328

@@ -32,7 +37,10 @@ impl DieselPool {
3237
// serving errors for the first connections until the pool is initialized) and if we can't
3338
// establish any connection continue booting up the application. The database pool will
3439
// automatically be marked as unhealthy and the rest of the application will adapt.
35-
let pool = DieselPool::Pool(config.build_unchecked(manager));
40+
let pool = DieselPool::Pool {
41+
pool: config.build_unchecked(manager),
42+
time_to_obtain_connection_metric,
43+
};
3644
match pool.wait_until_healthy(Duration::from_secs(5)) {
3745
Ok(()) => {}
3846
Err(PoolError::UnhealthyPool) => {}
@@ -52,22 +60,25 @@ impl DieselPool {
5260

5361
pub fn get(&self) -> Result<DieselPooledConn<'_>, PoolError> {
5462
match self {
55-
DieselPool::Pool(pool) => {
63+
DieselPool::Pool {
64+
pool,
65+
time_to_obtain_connection_metric,
66+
} => time_to_obtain_connection_metric.observe_closure_duration(|| {
5667
if let Some(conn) = pool.try_get() {
5768
Ok(DieselPooledConn::Pool(conn))
5869
} else if !self.is_healthy() {
5970
Err(PoolError::UnhealthyPool)
6071
} else {
6172
Ok(DieselPooledConn::Pool(pool.get().map_err(PoolError::R2D2)?))
6273
}
63-
}
74+
}),
6475
DieselPool::Test(conn) => Ok(DieselPooledConn::Test(conn.lock())),
6576
}
6677
}
6778

6879
pub fn state(&self) -> PoolState {
6980
match self {
70-
DieselPool::Pool(pool) => {
81+
DieselPool::Pool { pool, .. } => {
7182
let state = pool.state();
7283
PoolState {
7384
connections: state.connections,
@@ -83,7 +94,7 @@ impl DieselPool {
8394

8495
pub fn wait_until_healthy(&self, timeout: Duration) -> Result<(), PoolError> {
8596
match self {
86-
DieselPool::Pool(pool) => match pool.get_timeout(timeout) {
97+
DieselPool::Pool { pool, .. } => match pool.get_timeout(timeout) {
8798
Ok(_) => Ok(()),
8899
Err(_) if !self.is_healthy() => Err(PoolError::UnhealthyPool),
89100
Err(err) => Err(PoolError::R2D2(err)),

src/metrics/instance.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ metrics! {
2929
database_idle_conns: IntGaugeVec["pool"],
3030
/// Number of used database connections in the pool
3131
database_used_conns: IntGaugeVec["pool"],
32+
/// Amount of time required to obtain a database connection
33+
pub database_time_to_obtain_connection: HistogramVec["pool"],
3234

3335
/// Number of requests processed by this instance
3436
pub requests_total: IntCounter,

0 commit comments

Comments
 (0)