Skip to content

Commit 8f2edd2

Browse files
Automatically re-scan GitHub commits every 30 minutes
This lets us recover from faults in the GitHub API more quickly.
1 parent 02baf47 commit 8f2edd2

File tree

6 files changed

+67
-24
lines changed

6 files changed

+67
-24
lines changed

src/db.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::db::jobs::*;
21
use crate::handlers::jobs::handle_job;
2+
use crate::{db::jobs::*, handlers::Context};
33
use anyhow::Context as _;
44
use chrono::Utc;
55
use native_tls::{Certificate, TlsConnector};
@@ -198,14 +198,14 @@ pub async fn schedule_jobs(db: &DbClient, jobs: Vec<JobSchedule>) -> anyhow::Res
198198
Ok(())
199199
}
200200

201-
pub async fn run_scheduled_jobs(db: &DbClient) -> anyhow::Result<()> {
201+
pub async fn run_scheduled_jobs(ctx: &Context, db: &DbClient) -> anyhow::Result<()> {
202202
let jobs = get_jobs_to_execute(&db).await.unwrap();
203203
tracing::trace!("jobs to execute: {:#?}", jobs);
204204

205205
for job in jobs.iter() {
206206
update_job_executed_at(&db, &job.id).await?;
207207

208-
match handle_job(&job.name, &job.metadata).await {
208+
match handle_job(&ctx, &job.name, &job.metadata).await {
209209
Ok(_) => {
210210
tracing::trace!("job successfully executed (id={})", job.id);
211211
delete_job(&db, &job.id).await?;

src/handlers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ mod prioritize;
4343
mod relabel;
4444
mod review_submitted;
4545
mod rfc_helper;
46-
mod rustc_commits;
46+
pub mod rustc_commits;
4747
mod shortcut;
4848

4949
pub async fn handle(ctx: &Context, event: &Event) -> Vec<HandlerError> {

src/handlers/jobs.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,19 @@
44

55
// Further info could be find in src/jobs.rs
66

7-
pub async fn handle_job(name: &String, metadata: &serde_json::Value) -> anyhow::Result<()> {
7+
use super::Context;
8+
9+
pub async fn handle_job(
10+
ctx: &Context,
11+
name: &String,
12+
metadata: &serde_json::Value,
13+
) -> anyhow::Result<()> {
814
match name.as_str() {
915
"docs_update" => super::docs_update::handle_job().await,
16+
"rustc_commits" => {
17+
super::rustc_commits::synchronize_commits_inner(ctx, None).await;
18+
Ok(())
19+
}
1020
_ => default(&name, &metadata),
1121
}
1222
}

src/handlers/rustc_commits.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
use crate::db::jobs::JobSchedule;
12
use crate::db::rustc_commits;
23
use crate::db::rustc_commits::get_missing_commits;
34
use crate::{
45
github::{self, Event},
56
handlers::Context,
67
};
8+
use cron::Schedule;
79
use std::collections::VecDeque;
810
use std::convert::TryInto;
11+
use std::str::FromStr;
912
use tracing as log;
1013

1114
const BORS_GH_ID: i64 = 3372342;
@@ -80,16 +83,28 @@ pub async fn handle(ctx: &Context, event: &Event) -> anyhow::Result<()> {
8083
/// Fetch commits that are not present in the database.
8184
async fn synchronize_commits(ctx: &Context, sha: &str, pr: u32) {
8285
log::trace!("synchronize_commits for sha={:?}, pr={}", sha, pr);
86+
synchronize_commits_inner(ctx, Some((sha.to_owned(), pr))).await;
87+
}
88+
89+
pub async fn synchronize_commits_inner(ctx: &Context, starter: Option<(String, u32)>) {
8390
let db = ctx.db.get().await;
84-
let mut pr = Some(pr);
8591

8692
// List of roots to be resolved. Each root and its parents will be recursively resolved
8793
// until an existing commit is found.
8894
let mut to_be_resolved = VecDeque::new();
89-
to_be_resolved.push_back(sha.to_string());
90-
to_be_resolved.extend(get_missing_commits(&db).await);
95+
if let Some((sha, pr)) = starter {
96+
to_be_resolved.push_back((sha.to_string(), Some(pr)));
97+
}
98+
to_be_resolved.extend(
99+
get_missing_commits(&db)
100+
.await
101+
.into_iter()
102+
.map(|c| (c, None::<u32>)),
103+
);
104+
log::info!("synchronize_commits for {:?}", to_be_resolved);
91105

92-
while let Some(sha) = to_be_resolved.pop_front() {
106+
let db = ctx.db.get().await;
107+
while let Some((sha, mut pr)) = to_be_resolved.pop_front() {
93108
let mut gc = match ctx.github.rust_commit(&sha).await {
94109
Some(c) => c,
95110
None => {
@@ -130,14 +145,23 @@ async fn synchronize_commits(ctx: &Context, sha: &str, pr: u32) {
130145
match res {
131146
Ok(()) => {
132147
if !rustc_commits::has_commit(&db, &parent_sha).await {
133-
to_be_resolved.push_back(parent_sha)
148+
to_be_resolved.push_back((parent_sha, None))
134149
}
135150
}
136151
Err(e) => log::error!("Failed to record commit {:?}", e),
137152
}
138153
}
139154
}
140155

156+
pub fn job() -> JobSchedule {
157+
JobSchedule {
158+
name: "rustc_commits".to_string(),
159+
// Every 30 minutes...
160+
schedule: Schedule::from_str("* 0,30 * * * * *").unwrap(),
161+
metadata: serde_json::Value::Null,
162+
}
163+
}
164+
141165
#[derive(Debug, serde::Deserialize)]
142166
struct BorsMessage {
143167
#[serde(rename = "type")]

src/jobs.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ pub fn jobs() -> Vec<JobSchedule> {
4747
// Add to this vector any new cron task you want (as explained above)
4848
let mut jobs: Vec<JobSchedule> = Vec::new();
4949
jobs.push(crate::handlers::docs_update::job());
50+
jobs.push(crate::handlers::rustc_commits::job());
5051

5152
jobs
5253
}
54+
55+
#[test]
56+
fn jobs_defined() {
57+
// Checks we don't panic here, mostly for the schedule parsing.
58+
drop(jobs());
59+
}

src/main.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -267,18 +267,33 @@ async fn run_server(addr: SocketAddr) -> anyhow::Result<()> {
267267
}
268268
});
269269

270+
let client = Client::new();
271+
let gh = github::GithubClient::new_with_default_token(client.clone());
272+
let oc = octocrab::OctocrabBuilder::new()
273+
.personal_token(github::default_token_from_env())
274+
.build()
275+
.expect("Failed to build octograb.");
276+
let ctx = Arc::new(Context {
277+
username: String::from("rustbot"),
278+
db: pool,
279+
github: gh,
280+
octocrab: oc,
281+
});
282+
270283
// spawning a background task that will run the scheduled jobs
271284
// every JOB_PROCESSING_CADENCE_IN_SECS
285+
let ctx2 = ctx.clone();
272286
task::spawn(async move {
273287
loop {
288+
let ctx = ctx2.clone();
274289
let res = task::spawn(async move {
275290
let pool = db::ClientPool::new();
276291
let mut interval =
277292
time::interval(time::Duration::from_secs(JOB_PROCESSING_CADENCE_IN_SECS));
278293

279294
loop {
280295
interval.tick().await;
281-
db::run_scheduled_jobs(&*pool.get().await)
296+
db::run_scheduled_jobs(&ctx, &*pool.get().await)
282297
.await
283298
.context("run database scheduled jobs")
284299
.unwrap();
@@ -295,19 +310,6 @@ async fn run_server(addr: SocketAddr) -> anyhow::Result<()> {
295310
}
296311
});
297312

298-
let client = Client::new();
299-
let gh = github::GithubClient::new_with_default_token(client.clone());
300-
let oc = octocrab::OctocrabBuilder::new()
301-
.personal_token(github::default_token_from_env())
302-
.build()
303-
.expect("Failed to build octograb.");
304-
let ctx = Arc::new(Context {
305-
username: String::from("rustbot"),
306-
db: pool,
307-
github: gh,
308-
octocrab: oc,
309-
});
310-
311313
let agenda = tower::ServiceBuilder::new()
312314
.buffer(10)
313315
.layer_fn(|input| {

0 commit comments

Comments
 (0)