feat: worker crate, cargo-generate config, liquid templates, docker

This commit is contained in:
2026-05-18 00:26:17 +02:00
parent 1c5ae5d239
commit 5b0d5bf15d
15 changed files with 239 additions and 116 deletions

View File

@@ -0,0 +1,18 @@
#[derive(Debug, Clone)]
pub struct WorkerConfig {
pub database_url: String,
pub example_job_interval_secs: u64,
}
impl WorkerConfig {
pub fn from_env() -> Self {
dotenvy::dotenv().ok();
Self {
database_url: std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"),
example_job_interval_secs: std::env::var("EXAMPLE_JOB_INTERVAL_SECS")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(60),
}
}
}

7
crates/worker/src/job.rs Normal file
View File

@@ -0,0 +1,7 @@
use async_trait::async_trait;
#[async_trait]
pub trait Job: Send + Sync {
fn name(&self) -> &str;
async fn run(&self) -> anyhow::Result<()>;
}

View File

@@ -0,0 +1,14 @@
use async_trait::async_trait;
use tracing::info;
use crate::job::Job;
pub struct ExampleJob;
#[async_trait]
impl Job for ExampleJob {
fn name(&self) -> &str { "example" }
async fn run(&self) -> anyhow::Result<()> {
info!("example job ran — replace with real work");
Ok(())
}
}

View File

@@ -0,0 +1,2 @@
pub mod example;
pub use example::ExampleJob;

34
crates/worker/src/main.rs Normal file
View File

@@ -0,0 +1,34 @@
use std::sync::Arc;
use std::time::Duration;
use tracing::info;
mod config;
mod job;
mod jobs;
mod runner;
use jobs::ExampleJob;
use runner::JobRunner;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive("worker=info".parse()?),
)
.init();
let config = config::WorkerConfig::from_env();
info!("Worker starting");
let _pool = adapters_sqlite::connect(&config.database_url).await?;
adapters_sqlite::run_migrations(&_pool).await?;
let interval = Duration::from_secs(config.example_job_interval_secs);
let runner = JobRunner::new().register(Arc::new(ExampleJob), interval);
info!("Worker running");
runner.run().await;
Ok(())
}

View File

@@ -0,0 +1,34 @@
use std::sync::Arc;
use std::time::Duration;
use tracing::{error, info};
use crate::job::Job;
pub struct JobRunner {
jobs: Vec<(Arc<dyn Job>, Duration)>,
}
impl JobRunner {
pub fn new() -> Self { Self { jobs: vec![] } }
pub fn register(mut self, job: Arc<dyn Job>, interval: Duration) -> Self {
self.jobs.push((job, interval));
self
}
pub async fn run(self) {
let handles: Vec<_> = self.jobs.into_iter().map(|(job, interval)| {
tokio::spawn(async move {
loop {
info!(job = job.name(), "running job");
if let Err(e) = job.run().await {
error!(job = job.name(), error = %e, "job failed");
}
tokio::time::sleep(interval).await;
}
})
}).collect();
for handle in handles { let _ = handle.await; }
}
}
impl Default for JobRunner { fn default() -> Self { Self::new() } }