Skip to content

Commit c8154ee

Browse files
committed
add delay between build attempts
1 parent b879020 commit c8154ee

File tree

3 files changed

+83
-7
lines changed

3 files changed

+83
-7
lines changed

Diff for: src/build_queue.rs

+69-7
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ impl BuildQueue {
8383
ON CONFLICT (name, version) DO UPDATE
8484
SET priority = EXCLUDED.priority,
8585
registry = EXCLUDED.registry,
86-
attempt = 0
86+
attempt = 0,
87+
last_attempt = NULL
8788
;",
8889
&[&name, &version, &priority, &registry],
8990
)?;
@@ -179,11 +180,16 @@ impl BuildQueue {
179180
.query_opt(
180181
"SELECT id, name, version, priority, registry
181182
FROM queue
182-
WHERE attempt < $1
183+
WHERE
184+
attempt < $1 AND
185+
(last_attempt IS NULL OR last_attempt < NOW() - make_interval(secs => $2))
183186
ORDER BY priority ASC, attempt ASC, id ASC
184187
LIMIT 1
185188
FOR UPDATE SKIP LOCKED",
186-
&[&self.max_attempts],
189+
&[
190+
&self.max_attempts,
191+
&self.config.delay_between_build_attempts.as_secs_f64(),
192+
],
187193
)?
188194
.map(|row| QueuedCrate {
189195
id: row.get("id"),
@@ -219,7 +225,12 @@ impl BuildQueue {
219225
// Increase attempt count
220226
let attempt: i32 = transaction
221227
.query_one(
222-
"UPDATE queue SET attempt = attempt + 1 WHERE id = $1 RETURNING attempt;",
228+
"UPDATE queue
229+
SET
230+
attempt = attempt + 1,
231+
last_attempt = NOW()
232+
WHERE id = $1
233+
RETURNING attempt;",
223234
&[&to_process.id],
224235
)?
225236
.get(0);
@@ -502,6 +513,8 @@ impl BuildQueue {
502513
#[cfg(test)]
503514
mod tests {
504515
use super::*;
516+
use chrono::{DateTime, Utc};
517+
use std::time::Duration;
505518

506519
#[test]
507520
fn test_add_duplicate_doesnt_fail_last_priority_wins() {
@@ -531,8 +544,8 @@ mod tests {
531544
let mut conn = env.db().conn();
532545
conn.execute(
533546
"
534-
INSERT INTO queue (name, version, priority, attempt )
535-
VALUES ('failed_crate', '0.1.1', 0, 99)",
547+
INSERT INTO queue (name, version, priority, attempt, last_attempt )
548+
VALUES ('failed_crate', '0.1.1', 0, 99, NOW())",
536549
&[],
537550
)?;
538551

@@ -544,14 +557,15 @@ mod tests {
544557

545558
let row = conn
546559
.query_opt(
547-
"SELECT priority, attempt
560+
"SELECT priority, attempt, last_attempt
548561
FROM queue
549562
WHERE name = $1 AND version = $2",
550563
&[&"failed_crate", &"0.1.1"],
551564
)?
552565
.unwrap();
553566
assert_eq!(row.get::<_, i32>(0), 9);
554567
assert_eq!(row.get::<_, i32>(1), 0);
568+
assert!(row.get::<_, Option<DateTime<Utc>>>(2).is_none());
555569
Ok(())
556570
})
557571
}
@@ -574,13 +588,60 @@ mod tests {
574588
})
575589
}
576590

591+
#[test]
592+
fn test_wait_between_build_attempts() {
593+
crate::test::wrapper(|env| {
594+
env.override_config(|config| {
595+
config.build_attempts = 99;
596+
config.delay_between_build_attempts = Duration::from_secs(1);
597+
});
598+
599+
let queue = env.build_queue();
600+
601+
queue.add_crate("krate", "1.0.0", 0, None)?;
602+
603+
// first let it fail
604+
queue.process_next_crate(|krate| {
605+
assert_eq!(krate.name, "krate");
606+
anyhow::bail!("simulate a failure");
607+
})?;
608+
609+
queue.process_next_crate(|_| {
610+
// this can't happen since we didn't wait between attempts
611+
unreachable!();
612+
})?;
613+
614+
{
615+
// fake the build-attempt timestamp so it's older
616+
let mut conn = env.db().conn();
617+
conn.execute(
618+
"UPDATE queue SET last_attempt = $1",
619+
&[&(Utc::now() - chrono::Duration::seconds(60))],
620+
)?;
621+
}
622+
623+
let mut handled = false;
624+
// now we can process it again
625+
queue.process_next_crate(|krate| {
626+
assert_eq!(krate.name, "krate");
627+
handled = true;
628+
Ok(())
629+
})?;
630+
631+
assert!(handled);
632+
633+
Ok(())
634+
})
635+
}
636+
577637
#[test]
578638
fn test_add_and_process_crates() {
579639
const MAX_ATTEMPTS: u16 = 3;
580640

581641
crate::test::wrapper(|env| {
582642
env.override_config(|config| {
583643
config.build_attempts = MAX_ATTEMPTS;
644+
config.delay_between_build_attempts = Duration::ZERO;
584645
});
585646

586647
let queue = env.build_queue();
@@ -775,6 +836,7 @@ mod tests {
775836
crate::test::wrapper(|env| {
776837
env.override_config(|config| {
777838
config.build_attempts = MAX_ATTEMPTS;
839+
config.delay_between_build_attempts = Duration::ZERO;
778840
});
779841
let queue = env.build_queue();
780842

Diff for: src/config.rs

+5
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub struct Config {
9494

9595
// Build params
9696
pub(crate) build_attempts: u16,
97+
pub(crate) delay_between_build_attempts: Duration,
9798
pub(crate) rustwide_workspace: PathBuf,
9899
pub(crate) temp_dir: PathBuf,
99100
pub(crate) inside_docker: bool,
@@ -130,6 +131,10 @@ impl Config {
130131

131132
Ok(Self {
132133
build_attempts: env("DOCSRS_BUILD_ATTEMPTS", 5)?,
134+
delay_between_build_attempts: Duration::from_secs(env::<u64>(
135+
"DOCSRS_DELAY_BETWEEN_BUILD_ATTEMPTS",
136+
60,
137+
)?),
133138

134139
crates_io_api_call_retries: env("DOCSRS_CRATESIO_API_CALL_RETRIES", 3)?,
135140

Diff for: src/db/migrate.rs

+9
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,15 @@ pub fn migrate(version: Option<Version>, conn: &mut Client) -> crate::error::Res
896896
"ALTER TYPE feature DROP ATTRIBUTE optional_dependency;",
897897
"ALTER TYPE feature ADD ATTRIBUTE optional_dependency BOOL;"
898898
),
899+
sql_migration!(
900+
context,
901+
39,
902+
"Added last_attempt column to build queue",
903+
// upgrade query
904+
"ALTER TABLE queue ADD COLUMN last_attempt TIMESTAMP WITH TIME ZONE;",
905+
// downgrade query
906+
"ALTER TABLE queue DROP COLUMN last_attempt;"
907+
),
899908
];
900909

901910
for migration in migrations {

0 commit comments

Comments
 (0)