pub mod runner;
pub mod scheduler;
pub(crate) mod source;
pub mod warm;
use crate::store::{self, Db};
use chrono::Utc;
use shared::protocol::LogStream;
pub async fn recover_interrupted(db: &Db) -> anyhow::Result<usize> {
let abertas = store::job_run::list_unfinished(db).await?;
for run in &abertas {
let _ = store::job_log::append(
db,
&run.id,
&LogStream::Stderr,
"==> Execução interrompida: o daemon foi reiniciado antes de ela terminar \
(ou antes de começar, se ainda esperava a vez na fila)",
Utc::now(),
)
.await;
store::job_run::finish(db, &run.id, INTERRUPTED_EXIT_CODE).await?;
}
Ok(abertas.len())
}
pub const INTERRUPTED_EXIT_CODE: i32 = -1;
#[cfg(test)]
mod tests {
use super::*;
use ulid::Ulid;
async fn mem_db() -> Db {
let dir = std::env::temp_dir().join(format!("rustploy_test_{}", Ulid::new()));
store::connect(&dir).await.unwrap()
}
#[tokio::test]
async fn execucao_sem_fim_vira_interrompida_com_explicacao_no_log() {
let db = mem_db().await;
let esperando = store::job_run::create(&db, "j1").await.unwrap();
let terminada = store::job_run::create(&db, "j2").await.unwrap();
store::job_run::finish(&db, &terminada.id, 0).await.unwrap();
assert_eq!(recover_interrupted(&db).await.unwrap(), 1);
let r = store::job_run::get(&db, &esperando.id)
.await
.unwrap()
.unwrap();
assert!(r.finished_at.is_some(), "ganhou um fim");
assert_eq!(r.exit_code, Some(INTERRUPTED_EXIT_CODE));
assert_eq!(r.success, Some(false));
let log = store::job_log::get_for_run(&db, &esperando.id)
.await
.unwrap();
assert_eq!(log.len(), 1);
assert!(log[0].line.contains("interrompida"), "{}", log[0].line);
let t = store::job_run::get(&db, &terminada.id)
.await
.unwrap()
.unwrap();
assert_eq!(t.exit_code, Some(0));
assert_eq!(t.success, Some(true));
assert!(
store::job_log::get_for_run(&db, &terminada.id)
.await
.unwrap()
.is_empty()
);
assert_eq!(recover_interrupted(&db).await.unwrap(), 0);
}
}