Skip to content

Commit 41309b5

Browse files
committed
Implement a max_retries option.
This lets rebuilders set an upper limit for the number of times BAD packages will be retried.
1 parent b4a3e24 commit 41309b5

File tree

4 files changed

+54
-5
lines changed

4 files changed

+54
-5
lines changed

common/src/config.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,25 @@ impl WorkerConfig {
135135
#[derive(Debug, Default, Clone, Deserialize)]
136136
pub struct ScheduleConfig {
137137
retry_delay_base: Option<i64>,
138+
max_retries: Option<u64>,
138139
}
139140

140141
impl ScheduleConfig {
141142
pub fn update(&mut self, c: ScheduleConfig) {
142143
if c.retry_delay_base.is_some() {
143144
self.retry_delay_base = c.retry_delay_base;
144145
}
146+
147+
if c.max_retries.is_some() {
148+
self.max_retries = c.max_retries;
149+
}
145150
}
146151

147152
pub fn retry_delay_base(&self) -> i64 {
148153
self.retry_delay_base.unwrap_or(DEFAULT_RETRY_DELAY_BASE)
149154
}
155+
156+
pub fn max_retries(&self) -> Option<u64> {
157+
self.max_retries
158+
}
150159
}

contrib/confs/rebuilderd.conf

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@
3737
## Configure the delay to automatically retry failed rebuilds in hours. The
3838
## default is 24h, this base is multiplied with the number of rebuilds, so the
3939
## first retry would happen after 24h, the second retry would happen 48h after the
40-
## first retry and the third retry would happen 72h after the second retry. There
41-
## is no upper limit of retries, if you can't afford frequent retries it's
42-
## recommended to set this to a high value like 168 (1 week) or higher.
40+
## first retry and the third retry would happen 72h after the second retry. By default, there is no upper limit to the
41+
## number of retries; however, you may set one with max_retries.
4342
## Successful rebuilds are not retried.
4443
#retry_delay_base = 24
44+
45+
## Configure the maximum number of times an unreproducible package will be retried (0 to N). There is no default upper
46+
## limit.
47+
#max_retries =

daemon/src/api/v1/build.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::schema::{
1515
};
1616
use crate::{attestation, web};
1717
use actix_web::{get, post, HttpRequest, HttpResponse, Responder};
18-
use chrono::{Duration, Utc};
18+
use chrono::{Duration, NaiveDateTime, Utc};
1919
use diesel::dsl::update;
2020
use diesel::NullableExpressionMethods;
2121
use diesel::QueryDsl;
@@ -221,6 +221,20 @@ pub async fn submit_rebuild_report(
221221
.get_result::<i32>(connection.as_mut())
222222
.map_err(Error::from)?;
223223

224+
// bail if we have a max retry count set and requeueing this package would exceed it
225+
if let Some(max_retries) = cfg.schedule.max_retries() {
226+
if retry_count + 1 > max_retries as i32 {
227+
// null out the next retry to mark the package as non-retried
228+
update(build_inputs::table)
229+
.filter(build_inputs::id.eq_any(&friends))
230+
.set(build_inputs::next_retry.eq(None::<NaiveDateTime>))
231+
.execute(connection.as_mut())
232+
.map_err(Error::from)?;
233+
234+
return Ok(HttpResponse::NoContent());
235+
}
236+
}
237+
224238
let now = Utc::now();
225239
let then = now + Duration::hours(((retry_count + 1) * 24) as i64);
226240

daemon/src/api/v1/package.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::schema::{
1010
};
1111
use crate::web;
1212
use actix_web::{get, post, HttpRequest, HttpResponse, Responder};
13-
use chrono::Utc;
13+
use chrono::{NaiveDateTime, Utc};
1414
use diesel::dsl::{delete, exists, not, select, update};
1515
use diesel::r2d2::{ConnectionManager, PooledConnection};
1616
use diesel::sql_types::Integer;
@@ -242,6 +242,29 @@ pub async fn submit_package_report(
242242
let has_queued_friend = has_queued_friend(conn, &build_input)?;
243243

244244
if current_status != BuildStatus::Good && !has_queued_friend {
245+
let retry_count = build_inputs::table
246+
.filter(build_inputs::id.is(build_input.id))
247+
.select(build_inputs::retries)
248+
.get_result::<i32>(conn)?;
249+
250+
// bail if we have a max retry count set and requeueing this package would exceed it
251+
if let Some(max_retries) = cfg.schedule.max_retries() {
252+
if retry_count + 1 > max_retries as i32 {
253+
// null out the next retry to mark the package as non-retried
254+
update(build_inputs::table)
255+
.filter(build_inputs::id.eq(build_input.id))
256+
.set(build_inputs::next_retry.eq(None::<NaiveDateTime>))
257+
.execute(conn)?;
258+
259+
// drop any enqueued jobs for the build input
260+
delete(queue::table)
261+
.filter(queue::build_input_id.eq(build_input.id))
262+
.execute(conn)?;
263+
264+
return Ok::<(), Error>(());
265+
}
266+
}
267+
245268
let priority = match current_status {
246269
BuildStatus::Bad => Priority::retry(),
247270
_ => Priority::default(),

0 commit comments

Comments
 (0)