Skip to content

Commit b63607e

Browse files
committed
Auto merge of #2269 - rust-lang:sg-update-swirl-2020-03-10, r=jtgeibel
Update swirl This removes some of the boilerplate we had to add last night for manually managing connection pools with swirl. Swirl now can automatically manage its own connection pool. It can be given either a database URL, a pool builder, or a fully built pool (which is used in tests). If it's given one of the first two, it will configure the connection pool to have a size of 2x the thread count. I've also let it go up to the default number of threads, which is the number of CPU cores. Since this would mean the pool size grows pretty dramatically, I've configured it to not try to keep any idle connections (meaning it will try to establish the connection when asked for one, not before). Additionally, we no longer need the connection pool to live on our environment, we can take either a connection or a pool as an argument to a background job, and swirl will automatically take it from the pool. In the future I'm going to try and have swirl make some more intelligent decisions on this, so we could do something like have 2 threads only run jobs that don't need a connection (like publish!) Heroku doesn't guarantee the number of logical cores on standard dynos, but it appears to have consistently been 4 for a while. This means we'll be doubling the number of background workers, and potentially using up to 8 database connections on worker. Now that we've moved some web traffic to the replica, we may want to lower the pool size for the primary db on the web servers to compensate.
2 parents dc18552 + 893c5e3 commit b63607e

File tree

12 files changed

+36
-74
lines changed

12 files changed

+36
-74
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ dotenv = "0.15"
4848
toml = "0.4"
4949
diesel = { version = "1.4.0", features = ["postgres", "serde_json", "chrono", "r2d2"] }
5050
diesel_full_text_search = "1.0.0"
51-
swirl = { git = "https://github.com/sgrif/swirl.git", rev = "de5d8bb" }
51+
swirl = { git = "https://github.com/sgrif/swirl.git", rev = "6ef8c4cd" }
5252
serde_json = "1.0.0"
5353
serde = { version = "1.0.0", features = ["derive"] }
5454
chrono = { version = "0.4.0", features = ["serde"] }

src/background_jobs.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ impl swirl::db::DieselPool for DieselPool {
2424
#[allow(missing_debug_implementations)]
2525
pub struct Environment {
2626
index: Arc<Mutex<Repository>>,
27-
// FIXME: https://github.com/sfackler/r2d2/pull/70
28-
pub connection_pool: AssertUnwindSafe<DieselPool>,
2927
pub uploader: Uploader,
3028
http_client: AssertUnwindSafe<Client>,
3129
}
@@ -36,46 +34,29 @@ impl Clone for Environment {
3634
fn clone(&self) -> Self {
3735
Self {
3836
index: self.index.clone(),
39-
connection_pool: AssertUnwindSafe(self.connection_pool.0.clone()),
4037
uploader: self.uploader.clone(),
4138
http_client: AssertUnwindSafe(self.http_client.0.clone()),
4239
}
4340
}
4441
}
4542

4643
impl Environment {
47-
pub fn new(
48-
index: Repository,
49-
connection_pool: DieselPool,
50-
uploader: Uploader,
51-
http_client: Client,
52-
) -> Self {
53-
Self::new_shared(
54-
Arc::new(Mutex::new(index)),
55-
connection_pool,
56-
uploader,
57-
http_client,
58-
)
44+
pub fn new(index: Repository, uploader: Uploader, http_client: Client) -> Self {
45+
Self::new_shared(Arc::new(Mutex::new(index)), uploader, http_client)
5946
}
6047

6148
pub fn new_shared(
6249
index: Arc<Mutex<Repository>>,
63-
connection_pool: DieselPool,
6450
uploader: Uploader,
6551
http_client: Client,
6652
) -> Self {
6753
Self {
6854
index,
69-
connection_pool: AssertUnwindSafe(connection_pool),
7055
uploader,
7156
http_client: AssertUnwindSafe(http_client),
7257
}
7358
}
7459

75-
pub fn connection(&self) -> Result<DieselPooledConn<'_>, PoolError> {
76-
self.connection_pool.get()
77-
}
78-
7960
pub fn lock_index(&self) -> Result<MutexGuard<'_, Repository>, PerformError> {
8061
let repo = self.index.lock().unwrap_or_else(PoisonError::into_inner);
8162
repo.reset_head()?;

src/bin/background-worker.rs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ fn main() {
2424
println!("Booting runner");
2525

2626
let config = cargo_registry::Config::default();
27+
let db_url = db::connection_url(&config.db_url);
2728

2829
let job_start_timeout = dotenv::var("BACKGROUND_JOB_TIMEOUT")
2930
.unwrap_or_else(|_| "30".into())
@@ -39,22 +40,11 @@ fn main() {
3940
println!("Index cloned");
4041

4142
let build_runner = || {
42-
// 2x the thread pool size -- not all our jobs need a DB connection,
43-
// but we want to always be able to run our jobs in parallel, rather
44-
// than adjusting based on how many concurrent jobs need a connection.
45-
// Eventually swirl will do this for us, and this will be the default
46-
// -- we should just let it do a thread pool size of CPU count, and a
47-
// a connection pool size of 2x that when that lands.
48-
let db_config = r2d2::Pool::builder().max_size(4);
49-
let db_pool = db::diesel_pool(&config.db_url, config.env, db_config);
50-
let environment = Environment::new_shared(
51-
repository.clone(),
52-
db_pool.clone(),
53-
config.uploader.clone(),
54-
Client::new(),
55-
);
56-
swirl::Runner::builder(db_pool, environment)
57-
.thread_count(2)
43+
let environment =
44+
Environment::new_shared(repository.clone(), config.uploader.clone(), Client::new());
45+
let db_config = r2d2::Pool::builder().min_idle(Some(0));
46+
swirl::Runner::builder(environment)
47+
.connection_pool_builder(&db_url, db_config)
5848
.job_start_timeout(Duration::from_secs(job_start_timeout))
5949
.build()
6050
};

src/controllers/krate/publish.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ pub fn publish(req: &mut dyn Request) -> AppResult<Response> {
183183
.unwrap_or_else(|| String::from("README.md")),
184184
repo,
185185
)
186-
.enqueue(&conn)
187-
.map_err(|e| AppError::from_std_error(e))?;
186+
.enqueue(&conn)?;
188187
}
189188

190189
let cksum = app
@@ -204,9 +203,7 @@ pub fn publish(req: &mut dyn Request) -> AppResult<Response> {
204203
yanked: Some(false),
205204
links,
206205
};
207-
git::add_crate(git_crate)
208-
.enqueue(&conn)
209-
.map_err(|e| AppError::from_std_error(e))?;
206+
git::add_crate(git_crate).enqueue(&conn)?;
210207

211208
// The `other` field on `PublishWarnings` was introduced to handle a temporary warning
212209
// that is no longer needed. As such, crates.io currently does not return any `other`

src/controllers/version/yank.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ fn modify_yank(req: &mut dyn Request, yanked: bool) -> AppResult<Response> {
4444

4545
insert_version_owner_action(&conn, version.id, user.id, ids.api_token_id(), action)?;
4646

47-
git::yank(krate.name, version, yanked)
48-
.enqueue(&conn)
49-
.map_err(|e| AppError::from_std_error(e))?;
47+
git::yank(krate.name, version, yanked).enqueue(&conn)?;
5048

5149
ok_true()
5250
}

src/db.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,25 @@ pub fn connect_now() -> ConnectionResult<PgConnection> {
6363
PgConnection::establish(&url.to_string())
6464
}
6565

66-
pub fn diesel_pool(
67-
url: &str,
68-
env: Env,
69-
config: r2d2::Builder<ConnectionManager<PgConnection>>,
70-
) -> DieselPool {
66+
pub fn connection_url(url: &str) -> String {
7167
let mut url = Url::parse(url).expect("Invalid database URL");
7268
if dotenv::var("HEROKU").is_ok() && !url.query_pairs().any(|(k, _)| k == "sslmode") {
7369
url.query_pairs_mut().append_pair("sslmode", "require");
7470
}
71+
url.into_string()
72+
}
7573

74+
pub fn diesel_pool(
75+
url: &str,
76+
env: Env,
77+
config: r2d2::Builder<ConnectionManager<PgConnection>>,
78+
) -> DieselPool {
79+
let url = connection_url(url);
7680
if env == Env::Test {
77-
let conn =
78-
PgConnection::establish(&url.into_string()).expect("failed to establish connection");
81+
let conn = PgConnection::establish(&url).expect("failed to establish connection");
7982
DieselPool::test_conn(conn)
8083
} else {
81-
let manager = ConnectionManager::new(url.into_string());
84+
let manager = ConnectionManager::new(url);
8285
DieselPool::Pool(config.build(manager).unwrap())
8386
}
8487
}

src/git.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ pub fn add_crate(env: &Environment, krate: Crate) -> Result<(), PerformError> {
289289
/// push the changes.
290290
#[swirl::background_job]
291291
pub fn yank(
292+
conn: &PgConnection,
292293
env: &Environment,
293294
krate: String,
294295
version: Version,
@@ -299,8 +300,6 @@ pub fn yank(
299300
let repo = env.lock_index()?;
300301
let dst = repo.index_file(&krate);
301302

302-
let conn = env.connection()?;
303-
304303
conn.transaction(|| {
305304
let yanked_in_db = versions::table
306305
.find(version.id)

src/render.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ pub fn readme_to_html(text: &str, filename: &str, base_url: Option<&str>) -> Str
222222

223223
#[swirl::background_job]
224224
pub fn render_and_upload_readme(
225+
conn: &PgConnection,
225226
env: &Environment,
226227
version_id: i32,
227228
text: String,
@@ -232,7 +233,6 @@ pub fn render_and_upload_readme(
232233
use diesel::prelude::*;
233234

234235
let rendered = readme_to_html(&text, &file_name, base_url.as_deref());
235-
let conn = env.connection()?;
236236

237237
conn.transaction(|| {
238238
Version::record_readme_rendering(version_id, &conn)?;

src/tasks/update_downloads.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::{
2-
background_jobs::Environment,
32
models::VersionDownload,
43
schema::{crates, metadata, version_downloads, versions},
54
};
@@ -8,8 +7,7 @@ use diesel::prelude::*;
87
use swirl::PerformError;
98

109
#[swirl::background_job]
11-
pub fn update_downloads(env: &Environment) -> Result<(), PerformError> {
12-
let conn = env.connection()?;
10+
pub fn update_downloads(conn: &PgConnection) -> Result<(), PerformError> {
1311
update(&conn)?;
1412
Ok(())
1513
}

0 commit comments

Comments
 (0)