Skip to content

Commit 1b42e4c

Browse files
committed
Auto merge of #1669 - jtgeibel:remove-duplicate-dotenv-inits, r=sgrif
Remove duplicate initialization of `dotenv` While doing memory profiling, I noticed that `dotenv` was being initialized each time the `env` helper function was called. With my `.env` file in development it was (temporarily) allocating 9.7MB on each call to the `env` helper. The `dotenv::var` helper uses `std::sync::Once` and avoids this duplicate work. I don't expect this to improve allocation patterns on production much/any, as without a `.env` file, only 1.9kB is (temporarily) allocated. Some binaries will initialize sooner and will pick up some variables that would not previously work from `.env`.
2 parents ef78fb8 + afadfb7 commit 1b42e4c

17 files changed

+45
-73
lines changed

src/app.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Application-wide components in a struct accessible from each request
22
33
use crate::{db, util::CargoResult, Config, Env};
4-
use std::{env, path::PathBuf, sync::Arc, time::Duration};
4+
use std::{path::PathBuf, sync::Arc, time::Duration};
55

66
use diesel::r2d2;
77
use scheduled_thread_pool::ScheduledThreadPool;
@@ -45,25 +45,25 @@ impl App {
4545
);
4646
github.scopes.push(String::from("read:org"));
4747

48-
let db_pool_size = match (env::var("DB_POOL_SIZE"), config.env) {
48+
let db_pool_size = match (dotenv::var("DB_POOL_SIZE"), config.env) {
4949
(Ok(num), _) => num.parse().expect("couldn't parse DB_POOL_SIZE"),
5050
(_, Env::Production) => 10,
5151
_ => 1,
5252
};
5353

54-
let db_min_idle = match (env::var("DB_MIN_IDLE"), config.env) {
54+
let db_min_idle = match (dotenv::var("DB_MIN_IDLE"), config.env) {
5555
(Ok(num), _) => Some(num.parse().expect("couldn't parse DB_MIN_IDLE")),
5656
(_, Env::Production) => Some(5),
5757
_ => None,
5858
};
5959

60-
let db_helper_threads = match (env::var("DB_HELPER_THREADS"), config.env) {
60+
let db_helper_threads = match (dotenv::var("DB_HELPER_THREADS"), config.env) {
6161
(Ok(num), _) => num.parse().expect("couldn't parse DB_HELPER_THREADS"),
6262
(_, Env::Production) => 3,
6363
_ => 1,
6464
};
6565

66-
let db_connection_timeout = match (env::var("DB_TIMEOUT"), config.env) {
66+
let db_connection_timeout = match (dotenv::var("DB_TIMEOUT"), config.env) {
6767
(Ok(num), _) => num.parse().expect("couldn't parse DB_TIMEOUT"),
6868
(_, Env::Production) => 10,
6969
(_, Env::Test) => 1,

src/bin/background-worker.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use cargo_registry::git::Repository;
1313
use cargo_registry::{background_jobs::*, db};
1414
use diesel::r2d2;
15-
use std::env;
1615
use std::thread::sleep;
1716
use std::time::Duration;
1817

@@ -25,8 +24,8 @@ fn main() {
2524
let db_config = r2d2::Pool::builder().max_size(2);
2625
let db_pool = db::diesel_pool(&config.db_url, config.env, db_config);
2726

28-
let username = env::var("GIT_HTTP_USER");
29-
let password = env::var("GIT_HTTP_PWD");
27+
let username = dotenv::var("GIT_HTTP_USER");
28+
let password = dotenv::var("GIT_HTTP_PWD");
3029
let credentials = match (username, password) {
3130
(Ok(u), Ok(p)) => Some((u, p)),
3231
_ => None,

src/bin/monitor.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ mod on_call;
1313

1414
use cargo_registry::{db, util::CargoResult};
1515
use diesel::prelude::*;
16-
use std::env;
1716

1817
fn main() -> CargoResult<()> {
1918
let conn = db::connect_now()?;
@@ -30,7 +29,7 @@ fn check_stalled_background_jobs(conn: &PgConnection) -> CargoResult<()> {
3029

3130
println!("Checking for stalled background jobs");
3231

33-
let max_job_time = env::var("MAX_JOB_TIME")
32+
let max_job_time = dotenv::var("MAX_JOB_TIME")
3433
.map(|s| s.parse::<i32>().unwrap())
3534
.unwrap_or(15);
3635

src/bin/on_call/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use cargo_registry::util::{internal, CargoResult};
2-
use std::env;
32

43
use reqwest::{header, StatusCode as Status};
54

@@ -27,8 +26,8 @@ impl Event {
2726
/// If the variant is `Trigger`, this will page whoever is on call
2827
/// (potentially waking them up at 3 AM).
2928
pub fn send(self) -> CargoResult<()> {
30-
let api_token = env::var("PAGERDUTY_API_TOKEN")?;
31-
let service_key = env::var("PAGERDUTY_INTEGRATION_KEY")?;
29+
let api_token = dotenv::var("PAGERDUTY_API_TOKEN")?;
30+
let service_key = dotenv::var("PAGERDUTY_INTEGRATION_KEY")?;
3231

3332
let mut response = reqwest::Client::new()
3433
.post("https://events.pagerduty.com/generic/2010-04-15/create_event.json")

src/bin/server.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use cargo_registry::{boot, App, Env};
44
use jemalloc_ctl;
55
use std::{
6-
env,
76
fs::File,
87
sync::{mpsc::channel, Arc},
98
};
@@ -33,16 +32,16 @@ fn main() {
3332
let categories_toml = include_str!("../boot/categories.toml");
3433
boot::categories::sync(categories_toml).unwrap();
3534

36-
let heroku = env::var("HEROKU").is_ok();
35+
let heroku = dotenv::var("HEROKU").is_ok();
3736
let port = if heroku {
3837
8888
3938
} else {
40-
env::var("PORT")
39+
dotenv::var("PORT")
4140
.ok()
4241
.and_then(|s| s.parse().ok())
4342
.unwrap_or(8888)
4443
};
45-
let threads = env::var("SERVER_THREADS")
44+
let threads = dotenv::var("SERVER_THREADS")
4645
.map(|s| s.parse().expect("SERVER_THREADS was not a valid number"))
4746
.unwrap_or_else(|_| {
4847
if config.env == Env::Development {
@@ -52,7 +51,7 @@ fn main() {
5251
}
5352
});
5453

55-
let server = if env::var("USE_HYPER").is_ok() {
54+
let server = if dotenv::var("USE_HYPER").is_ok() {
5655
println!("Booting with a hyper based server");
5756
Hyper(HyperService::new(app, threads as usize))
5857
} else {

src/config.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{env, uploaders::Uploader, Env, Replica};
2-
use std::{env, path::PathBuf};
2+
use std::path::PathBuf;
33
use url::Url;
44

55
#[derive(Clone, Debug)]
@@ -43,12 +43,12 @@ impl Default for Config {
4343
fn default() -> Config {
4444
let checkout = PathBuf::from(env("GIT_REPO_CHECKOUT"));
4545
let api_protocol = String::from("https");
46-
let mirror = if env::var("MIRROR").is_ok() {
46+
let mirror = if dotenv::var("MIRROR").is_ok() {
4747
Replica::ReadOnlyMirror
4848
} else {
4949
Replica::Primary
5050
};
51-
let heroku = env::var("HEROKU").is_ok();
51+
let heroku = dotenv::var("HEROKU").is_ok();
5252
let cargo_env = if heroku {
5353
Env::Production
5454
} else {
@@ -62,12 +62,12 @@ impl Default for Config {
6262
Uploader::S3 {
6363
bucket: s3::Bucket::new(
6464
env("S3_BUCKET"),
65-
env::var("S3_REGION").ok(),
65+
dotenv::var("S3_REGION").ok(),
6666
env("S3_ACCESS_KEY"),
6767
env("S3_SECRET_KEY"),
6868
&api_protocol,
6969
),
70-
cdn: env::var("S3_CDN").ok(),
70+
cdn: dotenv::var("S3_CDN").ok(),
7171
proxy: None,
7272
}
7373
}
@@ -83,18 +83,18 @@ impl Default for Config {
8383
Uploader::S3 {
8484
bucket: s3::Bucket::new(
8585
env("S3_BUCKET"),
86-
env::var("S3_REGION").ok(),
87-
env::var("S3_ACCESS_KEY").unwrap_or_default(),
88-
env::var("S3_SECRET_KEY").unwrap_or_default(),
86+
dotenv::var("S3_REGION").ok(),
87+
dotenv::var("S3_ACCESS_KEY").unwrap_or_default(),
88+
dotenv::var("S3_SECRET_KEY").unwrap_or_default(),
8989
&api_protocol,
9090
),
91-
cdn: env::var("S3_CDN").ok(),
91+
cdn: dotenv::var("S3_CDN").ok(),
9292
proxy: None,
9393
}
9494
}
9595
// In Development mode, either running as a primary instance or a read-only mirror
9696
_ => {
97-
if env::var("S3_BUCKET").is_ok() {
97+
if dotenv::var("S3_BUCKET").is_ok() {
9898
// If we've set the `S3_BUCKET` variable to any value, use all of the values
9999
// for the related S3 environment variables and configure the app to upload to
100100
// and read from S3 like production does. All values except for bucket are
@@ -103,12 +103,12 @@ impl Default for Config {
103103
Uploader::S3 {
104104
bucket: s3::Bucket::new(
105105
env("S3_BUCKET"),
106-
env::var("S3_REGION").ok(),
107-
env::var("S3_ACCESS_KEY").unwrap_or_default(),
108-
env::var("S3_SECRET_KEY").unwrap_or_default(),
106+
dotenv::var("S3_REGION").ok(),
107+
dotenv::var("S3_ACCESS_KEY").unwrap_or_default(),
108+
dotenv::var("S3_SECRET_KEY").unwrap_or_default(),
109109
&api_protocol,
110110
),
111-
cdn: env::var("S3_CDN").ok(),
111+
cdn: dotenv::var("S3_CDN").ok(),
112112
proxy: None,
113113
}
114114
} else {

src/controllers/site_metadata.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use super::prelude::*;
66
/// If `HEROKU_SLUG_COMMIT` is not set, returns `"unknown"`.
77
pub fn show_deployed_sha(req: &mut dyn Request) -> CargoResult<Response> {
88
let deployed_sha =
9-
::std::env::var("HEROKU_SLUG_COMMIT").unwrap_or_else(|_| String::from("unknown"));
9+
dotenv::var("HEROKU_SLUG_COMMIT").unwrap_or_else(|_| String::from("unknown"));
1010

1111
#[derive(Serialize)]
1212
struct R<'a> {

src/controllers/user/session.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,10 @@ pub fn logout(req: &mut dyn Request) -> CargoResult<Response> {
133133
#[cfg(test)]
134134
mod tests {
135135
use super::*;
136-
use dotenv::dotenv;
137-
use std::env;
138136

139137
fn pg_connection() -> PgConnection {
140-
let _ = dotenv();
141138
let database_url =
142-
env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
139+
dotenv::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
143140
PgConnection::establish(&database_url).unwrap()
144141
}
145142

src/db.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::env;
2-
31
use conduit::Request;
42
use diesel::prelude::*;
53
use diesel::r2d2::{self, ConnectionManager, CustomizeConnection};
@@ -61,7 +59,7 @@ impl Deref for DieselPooledConn<'_> {
6159
pub fn connect_now() -> ConnectionResult<PgConnection> {
6260
use diesel::Connection;
6361
let mut url = Url::parse(&crate::env("DATABASE_URL")).expect("Invalid database URL");
64-
if env::var("HEROKU").is_ok() && !url.query_pairs().any(|(k, _)| k == "sslmode") {
62+
if dotenv::var("HEROKU").is_ok() && !url.query_pairs().any(|(k, _)| k == "sslmode") {
6563
url.query_pairs_mut().append_pair("sslmode", "require");
6664
}
6765
PgConnection::establish(&url.to_string())
@@ -73,7 +71,7 @@ pub fn diesel_pool(
7371
config: r2d2::Builder<ConnectionManager<PgConnection>>,
7472
) -> DieselPool {
7573
let mut url = Url::parse(url).expect("Invalid database URL");
76-
if env::var("HEROKU").is_ok() && !url.query_pairs().any(|(k, _)| k == "sslmode") {
74+
if dotenv::var("HEROKU").is_ok() && !url.query_pairs().any(|(k, _)| k == "sslmode") {
7775
url.query_pairs_mut().append_pair("sslmode", "require");
7876
}
7977

src/email.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
use std::env;
21
use std::path::Path;
32

43
use crate::util::{bad_request, CargoResult};
5-
use dotenv::dotenv;
64

75
use lettre::file::FileTransport;
86
use lettre::smtp::authentication::{Credentials, Mechanism};
@@ -19,12 +17,10 @@ pub struct MailgunConfigVars {
1917
}
2018

2119
pub fn init_config_vars() -> Option<MailgunConfigVars> {
22-
dotenv().ok();
23-
2420
match (
25-
env::var("MAILGUN_SMTP_LOGIN"),
26-
env::var("MAILGUN_SMTP_PASSWORD"),
27-
env::var("MAILGUN_SMTP_SERVER"),
21+
dotenv::var("MAILGUN_SMTP_LOGIN"),
22+
dotenv::var("MAILGUN_SMTP_PASSWORD"),
23+
dotenv::var("MAILGUN_SMTP_SERVER"),
2824
) {
2925
(Ok(login), Ok(password), Ok(server)) => Some(MailgunConfigVars {
3026
smtp_login: login,

src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ pub fn build_handler(app: Arc<App>) -> MiddlewareBuilder {
9595
/// Panics if the environment variable with the name passed in as an argument is not defined
9696
/// in the current environment.
9797
pub fn env(s: &str) -> String {
98-
dotenv::dotenv().ok();
99-
::std::env::var(s).unwrap_or_else(|_| panic!("must have `{}` defined", s))
98+
dotenv::var(s).unwrap_or_else(|_| panic!("must have `{}` defined", s))
10099
}
101100

102101
sql_function!(fn lower(x: ::diesel::sql_types::Text) -> ::diesel::sql_types::Text);

src/models/category.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,10 @@ impl<'a> NewCategory<'a> {
184184
mod tests {
185185
use super::*;
186186
use diesel::connection::SimpleConnection;
187-
use dotenv::dotenv;
188-
use std::env;
189187

190188
fn pg_connection() -> PgConnection {
191-
let _ = dotenv();
192189
let database_url =
193-
env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
190+
dotenv::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
194191
let conn = PgConnection::establish(&database_url).unwrap();
195192
// These tests deadlock if run concurrently
196193
conn.batch_execute("BEGIN; LOCK categories IN ACCESS EXCLUSIVE MODE")

src/models/keyword.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,10 @@ mod tests {
9999
use super::*;
100100
use diesel;
101101
use diesel::connection::SimpleConnection;
102-
use dotenv::dotenv;
103-
use std::env;
104102

105103
fn pg_connection() -> PgConnection {
106-
let _ = dotenv();
107104
let database_url =
108-
env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
105+
dotenv::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
109106
let conn = PgConnection::establish(&database_url).unwrap();
110107
// These tests deadlock if run concurrently
111108
conn.batch_execute("BEGIN;").unwrap();

src/tests/all.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use cargo_registry::{
2020
};
2121
use std::{
2222
borrow::Cow,
23-
env,
2423
sync::{
2524
atomic::{AtomicUsize, Ordering},
2625
Arc,
@@ -112,15 +111,13 @@ fn app() -> (
112111
Arc<App>,
113112
conduit_middleware::MiddlewareBuilder,
114113
) {
115-
dotenv::dotenv().ok();
116-
117114
let (proxy, bomb) = record::proxy();
118115
let uploader = Uploader::S3 {
119116
bucket: s3::Bucket::new(
120117
String::from("alexcrichton-test"),
121118
None,
122-
std::env::var("S3_ACCESS_KEY").unwrap_or_default(),
123-
std::env::var("S3_SECRET_KEY").unwrap_or_default(),
119+
dotenv::var("S3_ACCESS_KEY").unwrap_or_default(),
120+
dotenv::var("S3_SECRET_KEY").unwrap_or_default(),
124121
// When testing we route all API traffic over HTTP so we can
125122
// sniff/record it, but everywhere else we use https
126123
"http",
@@ -140,8 +137,8 @@ fn simple_app(uploader: Uploader) -> (Arc<App>, conduit_middleware::MiddlewareBu
140137
session_key: "test this has to be over 32 bytes long".to_string(),
141138
git_repo_checkout: git::checkout(),
142139
index_location: Url::from_file_path(&git::bare()).unwrap(),
143-
gh_client_id: env::var("GH_CLIENT_ID").unwrap_or_default(),
144-
gh_client_secret: env::var("GH_CLIENT_SECRET").unwrap_or_default(),
140+
gh_client_id: dotenv::var("GH_CLIENT_ID").unwrap_or_default(),
141+
gh_client_secret: dotenv::var("GH_CLIENT_SECRET").unwrap_or_default(),
145142
db_url: env("TEST_DATABASE_URL"),
146143
env: Env::Test,
147144
max_upload_size: 3000,
@@ -160,7 +157,7 @@ fn simple_app(uploader: Uploader) -> (Arc<App>, conduit_middleware::MiddlewareBu
160157

161158
// Return the environment variable only if it has been defined
162159
fn env(var: &str) -> String {
163-
match env::var(var) {
160+
match dotenv::var(var) {
164161
Ok(ref s) if s == "" => panic!("environment variable `{}` must not be empty", var),
165162
Ok(s) => s,
166163
_ => panic!(

src/tests/categories.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use cargo_registry::schema::categories;
2-
use std::env;
32

43
use diesel::*;
5-
use dotenv::dotenv;
64

75
const ALGORITHMS: &str = r#"
86
[algorithms]
@@ -40,9 +38,8 @@ description = "Another category ho hum"
4038
"#;
4139

4240
fn pg_connection() -> PgConnection {
43-
let _ = dotenv();
4441
let database_url =
45-
env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
42+
dotenv::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set to run tests");
4643
let conn = PgConnection::establish(&database_url).unwrap();
4744
conn.begin_test_transaction().unwrap();
4845
conn

0 commit comments

Comments
 (0)