mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-05-20 10:33:55 +00:00
Add a generic job scheduler
Also rewrite deletion of old sends using the job scheduler.
This commit is contained in:
parent
a82c04910f
commit
73ff8d79f7
9 changed files with 126 additions and 31 deletions
|
@ -5,7 +5,7 @@ mod organizations;
|
|||
pub mod two_factor;
|
||||
mod sends;
|
||||
|
||||
pub use sends::start_send_deletion_scheduler;
|
||||
pub use sends::purge_sends;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
let mut mod_routes = routes![
|
||||
|
|
|
@ -9,7 +9,7 @@ use serde_json::Value;
|
|||
use crate::{
|
||||
api::{ApiResult, EmptyResult, JsonResult, JsonUpcase, Notify, UpdateType},
|
||||
auth::{Headers, Host},
|
||||
db::{models::*, DbConn},
|
||||
db::{models::*, DbConn, DbPool},
|
||||
CONFIG,
|
||||
};
|
||||
|
||||
|
@ -27,21 +27,13 @@ pub fn routes() -> Vec<rocket::Route> {
|
|||
]
|
||||
}
|
||||
|
||||
pub fn start_send_deletion_scheduler(pool: crate::db::DbPool) {
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
if let Ok(conn) = pool.get() {
|
||||
info!("Initiating send deletion");
|
||||
for send in Send::find_all(&conn) {
|
||||
if chrono::Utc::now().naive_utc() >= send.deletion_date {
|
||||
send.delete(&conn).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_secs(3600));
|
||||
}
|
||||
});
|
||||
pub fn purge_sends(pool: DbPool) {
|
||||
debug!("Purging sends");
|
||||
if let Ok(conn) = pool.get() {
|
||||
Send::purge(&conn);
|
||||
} else {
|
||||
error!("Failed to get DB connection while purging sends")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
|
|
@ -10,8 +10,8 @@ use serde_json::Value;
|
|||
|
||||
pub use crate::api::{
|
||||
admin::routes as admin_routes,
|
||||
core::purge_sends,
|
||||
core::routes as core_routes,
|
||||
core::start_send_deletion_scheduler,
|
||||
icons::routes as icons_routes,
|
||||
identity::routes as identity_routes,
|
||||
notifications::routes as notifications_routes,
|
||||
|
|
|
@ -316,6 +316,14 @@ make_config! {
|
|||
/// Websocket port
|
||||
websocket_port: u16, false, def, 3012;
|
||||
},
|
||||
jobs {
|
||||
/// Job scheduler poll interval |> How often the job scheduler thread checks for jobs to run.
|
||||
/// Set to 0 to globally disable scheduled jobs.
|
||||
job_poll_interval_ms: u64, false, def, 30_000;
|
||||
/// Send purge schedule |> Cron schedule of the job that checks for Sends past their deletion date.
|
||||
/// Defaults to hourly. Set blank to disable this job.
|
||||
send_purge_schedule: String, false, def, "0 0 * * * *".to_string();
|
||||
},
|
||||
|
||||
/// General settings
|
||||
settings {
|
||||
|
|
|
@ -205,6 +205,13 @@ impl Send {
|
|||
}}
|
||||
}
|
||||
|
||||
/// Purge all sends that are past their deletion date.
|
||||
pub fn purge(conn: &DbConn) {
|
||||
for send in Self::find_by_past_deletion_date(&conn) {
|
||||
send.delete(&conn).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_users_revision(&self, conn: &DbConn) {
|
||||
match &self.user_uuid {
|
||||
Some(user_uuid) => {
|
||||
|
@ -223,12 +230,6 @@ impl Send {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_all(conn: &DbConn) -> Vec<Self> {
|
||||
db_run! {conn: {
|
||||
sends::table.load::<SendDb>(conn).expect("Error loading sends").from_db()
|
||||
}}
|
||||
}
|
||||
|
||||
pub fn find_by_access_id(access_id: &str, conn: &DbConn) -> Option<Self> {
|
||||
use data_encoding::BASE64URL_NOPAD;
|
||||
use uuid::Uuid;
|
||||
|
@ -271,4 +272,13 @@ impl Send {
|
|||
.load::<SendDb>(conn).expect("Error loading sends").from_db()
|
||||
}}
|
||||
}
|
||||
|
||||
pub fn find_by_past_deletion_date(conn: &DbConn) -> Vec<Self> {
|
||||
let now = Utc::now().naive_utc();
|
||||
db_run! {conn: {
|
||||
sends::table
|
||||
.filter(sends::deletion_date.lt(now))
|
||||
.load::<SendDb>(conn).expect("Error loading sends").from_db()
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -16,6 +16,7 @@ extern crate diesel;
|
|||
#[macro_use]
|
||||
extern crate diesel_migrations;
|
||||
|
||||
use job_scheduler::{JobScheduler, Job};
|
||||
use std::{
|
||||
fs::create_dir_all,
|
||||
panic,
|
||||
|
@ -23,6 +24,7 @@ use std::{
|
|||
process::{exit, Command},
|
||||
str::FromStr,
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
#[macro_use]
|
||||
|
@ -56,7 +58,9 @@ fn main() {
|
|||
|
||||
create_icon_cache_folder();
|
||||
|
||||
launch_rocket(extra_debug);
|
||||
let pool = create_db_pool();
|
||||
schedule_jobs(pool.clone());
|
||||
launch_rocket(pool, extra_debug); // Blocks until program termination.
|
||||
}
|
||||
|
||||
const HELP: &str = "\
|
||||
|
@ -301,17 +305,17 @@ fn check_web_vault() {
|
|||
}
|
||||
}
|
||||
|
||||
fn launch_rocket(extra_debug: bool) {
|
||||
let pool = match util::retry_db(db::DbPool::from_config, CONFIG.db_connection_retries()) {
|
||||
fn create_db_pool() -> db::DbPool {
|
||||
match util::retry_db(db::DbPool::from_config, CONFIG.db_connection_retries()) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
error!("Error creating database pool: {:?}", e);
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
api::start_send_deletion_scheduler(pool.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn launch_rocket(pool: db::DbPool, extra_debug: bool) {
|
||||
let basepath = &CONFIG.domain_path();
|
||||
|
||||
// If adding more paths here, consider also adding them to
|
||||
|
@ -334,3 +338,30 @@ fn launch_rocket(extra_debug: bool) {
|
|||
// The launch will restore the original logging level
|
||||
error!("Launch error {:#?}", result);
|
||||
}
|
||||
|
||||
fn schedule_jobs(pool: db::DbPool) {
|
||||
if CONFIG.job_poll_interval_ms() == 0 {
|
||||
info!("Job scheduler disabled.");
|
||||
return;
|
||||
}
|
||||
thread::Builder::new().name("job-scheduler".to_string()).spawn(move || {
|
||||
let mut sched = JobScheduler::new();
|
||||
|
||||
// Purge sends that are past their deletion date.
|
||||
if !CONFIG.send_purge_schedule().is_empty() {
|
||||
sched.add(Job::new(CONFIG.send_purge_schedule().parse().unwrap(), || {
|
||||
api::purge_sends(pool.clone());
|
||||
}));
|
||||
}
|
||||
|
||||
// Periodically check for jobs to run. We probably won't need any
|
||||
// jobs that run more often than once a minute, so a default poll
|
||||
// interval of 30 seconds should be sufficient. Users who want to
|
||||
// schedule jobs to run more frequently for some reason can reduce
|
||||
// the poll interval accordingly.
|
||||
loop {
|
||||
sched.tick();
|
||||
thread::sleep(Duration::from_millis(CONFIG.job_poll_interval_ms()));
|
||||
}
|
||||
}).expect("Error spawning job scheduler thread");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue