Skip to content

Commit 06bfd00

Browse files
committed
Auto merge of #2432 - sgrif:sg-update-swirl-04-16-2020, r=jtgeibel
Update Swirl, take two This is a second attempt at #2269, which had to be reverted shortly after being deployed, as it caused jobs to fail to run in production. This commit only differs from that PR in the revision of swirl used. The cause of the issue was the change in the signature of `update_downloads`, which does not need anything from the job environment, and so it only takes a connection. This changed the environment type for that job from `background_jobs::Environment` to `()`, so our runner no longer knew how to run that job. The smallest fix in crates.io would have been to add an unused environment argument to `update_downloads`. However, having some jobs not require a shared environment felt common enough that I fixed this in swirl instead. sgrif/swirl#23 changed the behavior so jobs with no environment (a.k.a. the environment type is `()`) are always run, regardless of the environment type of the runner. Since `update_downloads` is essentially a cron job, and is not enqueued from the web server directly, this was not caught by our integration suite. This case was caught quickly after being deployed, and only affected a non-critical part of the service, so I've opted not to figure out how to add this to our integration suite. r? @jtgeibel
2 parents fe4e0a2 + 97d7fc8 commit 06bfd00

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.5"
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 = "e87cf37" }
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 RequestExt) -> EndpointResult {
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 RequestExt) -> EndpointResult {
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 RequestExt, yanked: bool) -> EndpointResult {
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
}

src/tests/util.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl Drop for TestAppInner {
7777
// Lazily run any remaining jobs
7878
if let Some(runner) = &self.runner {
7979
runner.run_all_pending_jobs().expect("Could not run jobs");
80-
runner.assert_no_failed_jobs().expect("Failed jobs remain");
80+
runner.check_for_failed_jobs().expect("Failed jobs remain");
8181
}
8282

8383
// Manually verify that all jobs have completed successfully
@@ -192,7 +192,7 @@ impl TestApp {
192192

193193
runner.run_all_pending_jobs().expect("Could not run jobs");
194194
runner
195-
.assert_no_failed_jobs()
195+
.check_for_failed_jobs()
196196
.expect("Could not determine if jobs failed");
197197
}
198198

@@ -223,24 +223,23 @@ impl TestAppBuilder {
223223
let (app, middle) = crate::build_app(self.config, self.proxy);
224224

225225
let runner = if self.build_job_runner {
226-
let connection_pool = app.primary_database.clone();
227226
let repository_config = RepositoryConfig {
228227
index_location: Url::from_file_path(&git::bare()).unwrap(),
229228
credentials: Credentials::Missing,
230229
};
231230
let index = WorkerRepository::open(&repository_config).expect("Could not clone index");
232231
let environment = Environment::new(
233232
index,
234-
connection_pool.clone(),
235233
app.config.uploader.clone(),
236234
app.http_client().clone(),
237235
);
238236

239237
Some(
240-
Runner::builder(connection_pool, environment)
238+
Runner::builder(environment)
241239
// We only have 1 connection in tests, so trying to run more than
242240
// 1 job concurrently will just block
243241
.thread_count(1)
242+
.connection_pool(app.primary_database.clone())
244243
.job_start_timeout(Duration::from_secs(5))
245244
.build(),
246245
)

src/util/errors.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ impl dyn AppError {
9797
self.get_type_id() == TypeId::of::<T>()
9898
}
9999

100-
pub fn from_std_error(err: Box<dyn Error + Send>) -> Box<dyn AppError> {
101-
Self::try_convert(&*err).unwrap_or_else(|| internal(&err))
102-
}
103-
104100
fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
105101
match err.downcast_ref() {
106102
Some(DieselError::NotFound) => Some(Box::new(NotFound)),

0 commit comments

Comments
 (0)