Add job trait and state data objects
Signed-off-by: trivernis <trivernis@protonmail.com>feature/jobs
parent
8b342f6aac
commit
530fbd7606
@ -0,0 +1,20 @@
|
||||
use crate::dao::job::JobDao;
|
||||
use crate::dto::JobStateDto;
|
||||
use mediarepo_core::error::RepoResult;
|
||||
use mediarepo_database::entities::job_state;
|
||||
use sea_orm::prelude::*;
|
||||
|
||||
impl JobDao {
|
||||
/// Returns all job states for a given job id
|
||||
pub async fn states_for_job_id(&self, job_id: i64) -> RepoResult<Vec<JobStateDto>> {
|
||||
let states = job_state::Entity::find()
|
||||
.filter(job_state::Column::JobId.eq(job_id))
|
||||
.all(&self.ctx.db)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(JobStateDto::new)
|
||||
.collect();
|
||||
|
||||
Ok(states)
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use mediarepo_database::entities::job;
|
||||
use mediarepo_database::entities::job::JobType;
|
||||
|
||||
pub struct JobDto {
|
||||
model: job::Model,
|
||||
}
|
||||
|
||||
impl JobDto {
|
||||
pub(crate) fn new(model: job::Model) -> Self {
|
||||
Self { model }
|
||||
}
|
||||
|
||||
pub fn id(&self) -> i64 {
|
||||
self.model.id
|
||||
}
|
||||
|
||||
pub fn job_type(&self) -> JobType {
|
||||
self.model.job_type
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Option<&String> {
|
||||
self.model.name.as_ref()
|
||||
}
|
||||
|
||||
pub fn next_run(&self) -> Option<NaiveDateTime> {
|
||||
self.model.next_run
|
||||
}
|
||||
|
||||
pub fn interval(&self) -> Option<i64> {
|
||||
self.model.interval
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
use mediarepo_database::entities::job_state;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct JobStateDto {
|
||||
model: job_state::Model,
|
||||
}
|
||||
|
||||
impl JobStateDto {
|
||||
pub(crate) fn new(model: job_state::Model) -> Self {
|
||||
Self { model }
|
||||
}
|
||||
|
||||
pub fn job_id(&self) -> i64 {
|
||||
self.model.job_id
|
||||
}
|
||||
|
||||
pub fn key(&self) -> &String {
|
||||
&self.model.key
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &[u8] {
|
||||
&self.model.value
|
||||
}
|
||||
|
||||
pub fn into_value(self) -> Vec<u8> {
|
||||
self.model.value
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UpsertJobStateDto {
|
||||
pub job_id: i64,
|
||||
pub key: String,
|
||||
pub value: Vec<u8>,
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "mediarepo-worker"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.52"
|
||||
|
||||
[dependencies.mediarepo-core]
|
||||
path = "../mediarepo-core"
|
||||
|
||||
[dependencies.mediarepo-logic]
|
||||
path = "../mediarepo-logic"
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1.17.0"
|
||||
features = []
|
||||
|
||||
[dependencies.chrono]
|
||||
version = "0.4.19"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.136"
|
||||
features = ["derive"]
|
@ -0,0 +1,23 @@
|
||||
use crate::state_data::StateData;
|
||||
use async_trait::async_trait;
|
||||
use mediarepo_core::error::RepoResult;
|
||||
use mediarepo_logic::dao::repo::Repo;
|
||||
use mediarepo_logic::dto::JobDto;
|
||||
|
||||
#[async_trait]
|
||||
pub trait ScheduledJob {
|
||||
fn new(dto: JobDto) -> Self;
|
||||
|
||||
async fn set_state(&self, state: StateData) -> RepoResult<()>;
|
||||
|
||||
async fn run(&self, repo: Repo) -> RepoResult<()>;
|
||||
|
||||
fn execution_state(&self) -> JobExecutionState;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum JobExecutionState {
|
||||
Scheduled,
|
||||
Running,
|
||||
Finished,
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
pub mod jobs;
|
||||
pub mod scheduler;
|
||||
pub mod state_data;
|
@ -0,0 +1,7 @@
|
||||
use mediarepo_logic::dao::repo::Repo;
|
||||
|
||||
pub struct Scheduler {
|
||||
pub repo: Repo,
|
||||
}
|
||||
|
||||
impl Scheduler {}
|
@ -0,0 +1,84 @@
|
||||
use mediarepo_core::bincode;
|
||||
use mediarepo_core::error::RepoResult;
|
||||
use mediarepo_logic::dao::job::JobDao;
|
||||
use mediarepo_logic::dto::UpsertJobStateDto;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StateData {
|
||||
job_id: i64,
|
||||
inner: Arc<RwLock<HashMap<String, Vec<u8>>>>,
|
||||
changed_keys: Arc<RwLock<HashSet<String>>>,
|
||||
}
|
||||
|
||||
impl StateData {
|
||||
/// Loads the state from the database
|
||||
pub async fn load(job_dao: JobDao, job_id: i64) -> RepoResult<Self> {
|
||||
let states = job_dao.states_for_job_id(job_id).await?;
|
||||
let states_map = states
|
||||
.into_iter()
|
||||
.map(|s| (s.key().to_owned(), s.into_value()))
|
||||
.collect::<HashMap<String, Vec<u8>>>();
|
||||
|
||||
Ok(Self {
|
||||
job_id,
|
||||
inner: Arc::new(RwLock::new(states_map)),
|
||||
changed_keys: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the deserialized copy of a state object from the inner map
|
||||
pub async fn entry<S: AsRef<str>, T: DeserializeOwned>(&self, key: S) -> RepoResult<Option<T>> {
|
||||
let entries = self.inner.read().await;
|
||||
let entry = entries.get(key.as_ref());
|
||||
|
||||
if let Some(bytes) = entry {
|
||||
let value = bincode::deserialize(bytes)?;
|
||||
|
||||
Ok(Some(value))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores an entry in inner map
|
||||
pub async fn store_entry<T: Serialize>(&self, key: String, value: &T) -> RepoResult<()> {
|
||||
let entry_bytes = bincode::serialize(value)?;
|
||||
let mut entries = self.inner.write().await;
|
||||
entries.insert(key.clone(), entry_bytes);
|
||||
let mut changed_entries = self.changed_keys.write().await;
|
||||
changed_entries.insert(key);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a list of all changed state objects as an upsert list
|
||||
pub async fn changed_states(&self) -> Vec<UpsertJobStateDto> {
|
||||
let mut upsert_list = Vec::new();
|
||||
|
||||
{
|
||||
let changed_keys = self.changed_keys.read().await;
|
||||
let entries = self.inner.read().await;
|
||||
|
||||
for key in &*changed_keys {
|
||||
if let Some(value) = entries.get(key) {
|
||||
upsert_list.push(UpsertJobStateDto {
|
||||
job_id: self.job_id,
|
||||
key: key.to_owned(),
|
||||
value: value.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut changed_keys = self.changed_keys.write().await;
|
||||
changed_keys.clear();
|
||||
}
|
||||
|
||||
upsert_list
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue