Skip to content

Commit f7a9b4a

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 4f9617d commit f7a9b4a

File tree

4 files changed

+55
-6
lines changed

4 files changed

+55
-6
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: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ 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;
20-
use diesel::NullableExpressionMethods;
2120
use diesel::QueryDsl;
2221
use diesel::{ExpressionMethods, SqliteExpressionMethods};
22+
use diesel::NullableExpressionMethods;
2323
use diesel::{OptionalExtension, RunQueryDsl};
2424
use in_toto::crypto::PrivateKey;
2525
use rebuilderd_common::api;
@@ -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
@@ -11,7 +11,7 @@ use crate::schema::{
1111
};
1212
use crate::web;
1313
use actix_web::{get, post, HttpRequest, HttpResponse, Responder};
14-
use chrono::Utc;
14+
use chrono::{NaiveDateTime, Utc};
1515
use diesel::dsl::{delete, exists, not, select, update};
1616
use diesel::r2d2::{ConnectionManager, PooledConnection};
1717
use diesel::sql_types::Integer;
@@ -243,6 +243,29 @@ pub async fn submit_package_report(
243243
let has_queued_friend = has_queued_friend(conn, &build_input)?;
244244

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

0 commit comments

Comments
 (0)