Implement periodic job dispatching

Signed-off-by: trivernis <trivernis@protonmail.com>
feature/jobs
trivernis 3 years ago
parent 056166ee60
commit a57a6f32c4
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -5,7 +5,9 @@ use mediarepo_logic::dao::repo::Repo;
use mediarepo_logic::dao::DaoProvider; use mediarepo_logic::dao::DaoProvider;
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tokio::time::Instant;
#[derive(Clone)] #[derive(Clone)]
pub struct JobDispatcher { pub struct JobDispatcher {
@ -23,8 +25,24 @@ impl JobDispatcher {
} }
} }
#[tracing::instrument(level = "debug", skip_all)]
pub async fn dispatch<T: 'static + Job>(&self, job: T) -> Arc<RwLock<T::JobStatus>> { pub async fn dispatch<T: 'static + Job>(&self, job: T) -> Arc<RwLock<T::JobStatus>> {
self._dispatch(job, None).await
}
pub async fn dispatch_periodically<T: 'static + Job>(
&self,
job: T,
interval: Duration,
) -> Arc<RwLock<T::JobStatus>> {
self._dispatch(job, Some(interval)).await
}
#[tracing::instrument(level = "debug", skip_all)]
async fn _dispatch<T: 'static + Job>(
&self,
job: T,
interval: Option<Duration>,
) -> Arc<RwLock<T::JobStatus>> {
let status = job.status(); let status = job.status();
self.add_status::<JobTypeKey<T>>(status.clone()).await; self.add_status::<JobTypeKey<T>>(status.clone()).await;
@ -37,23 +55,35 @@ impl JobDispatcher {
let repo = self.repo.clone(); let repo = self.repo.clone();
subsystem.start("worker-job", |subsystem| async move { subsystem.start("worker-job", move |subsystem| async move {
let job_2 = job.clone(); loop {
let result = tokio::select! { let start = Instant::now();
_ = subsystem.on_shutdown_requested() => { let job_2 = job.clone();
job_2.save_status(repo.job()).await let result = tokio::select! {
} _ = subsystem.on_shutdown_requested() => {
r = job.run(repo.clone()) => { job_2.save_status(repo.job()).await
}
r = job.run(repo.clone()) => {
if let Err(e) = r { if let Err(e) = r {
Err(e) Err(e)
} else { } else {
job.save_status(repo.job()).await job.save_status(repo.job()).await
}
}
};
if let Err(e) = result {
tracing::error!("job failed with error: {}", e);
}
if let Some(interval) = interval {
let sleep_duration = interval - start.elapsed();
tokio::select! {
_ = tokio::time::sleep(sleep_duration) => {},
_ = subsystem.on_shutdown_requested() => {break}
} }
} else {
break;
} }
};
if let Err(e) = result {
tracing::error!("job failed with error: {}", e);
} }
Ok(()) Ok(())

@ -3,6 +3,7 @@ use crate::jobs::VacuumJob;
use mediarepo_core::error::RepoError; use mediarepo_core::error::RepoError;
use mediarepo_core::tokio_graceful_shutdown::Toplevel; use mediarepo_core::tokio_graceful_shutdown::Toplevel;
use mediarepo_logic::dao::repo::Repo; use mediarepo_logic::dao::repo::Repo;
use std::time::Duration;
use tokio::sync::oneshot::channel; use tokio::sync::oneshot::channel;
pub mod job_dispatcher; pub mod job_dispatcher;
@ -15,7 +16,9 @@ pub async fn start(top_level: Toplevel, repo: Repo) -> (Toplevel, JobDispatcher)
let dispatcher = JobDispatcher::new(subsystem, repo); let dispatcher = JobDispatcher::new(subsystem, repo);
tx.send(dispatcher.clone()) tx.send(dispatcher.clone())
.map_err(|_| RepoError::from("failed to send dispatcher"))?; .map_err(|_| RepoError::from("failed to send dispatcher"))?;
dispatcher.dispatch(VacuumJob::default()).await; dispatcher
.dispatch_periodically(VacuumJob::default(), Duration::from_secs(60 * 30))
.await;
Ok(()) Ok(())
}); });

Loading…
Cancel
Save