feedsignal/crates/web/src/server/jobs/mod.rs

75 lines
2.2 KiB
Rust
Raw Normal View History

mod affinity_decay;
mod feed_polling;
mod scoring;
use anyhow::Result;
use feedsignal_db::Db;
use feedsignal_llm::Llm;
use std::sync::Arc;
use tokio_cron_scheduler::{Job, JobScheduler};
/// Wires up the recurring jobs described in the design discussion: polling
/// subscribed feeds for new articles, scoring them, and decaying topic
/// affinities once a day so stale signals fade. Call once at server
/// startup, and also runs once immediately so a freshly (re)opened app
/// doesn't wait 15 minutes for its first check.
pub async fn start_scheduler(db: Arc<Db>, llm: Arc<Llm>) -> Result<JobScheduler> {
let scheduler = JobScheduler::new().await?;
{
let db = db.clone();
tokio::spawn(async move {
if let Err(err) = feed_polling::run(&db).await {
tracing::error!(?err, "initial feed poll failed");
}
});
}
{
let db = db.clone();
scheduler
.add(Job::new_async("0 */15 * * * *", move |_uuid, _lock| {
let db = db.clone();
Box::pin(async move {
if let Err(err) = feed_polling::run(&db).await {
tracing::error!(?err, "feed polling run failed");
}
})
})?)
.await?;
}
{
let db = db.clone();
let llm = llm.clone();
scheduler
.add(Job::new_async("0 */15 * * * *", move |_uuid, _lock| {
let db = db.clone();
let llm = llm.clone();
Box::pin(async move {
if let Err(err) = scoring::run(&db, &llm).await {
tracing::error!(?err, "scoring pipeline run failed");
}
})
})?)
.await?;
}
{
let db = db.clone();
scheduler
.add(Job::new_async("0 0 4 * * *", move |_uuid, _lock| {
let db = db.clone();
Box::pin(async move {
if let Err(err) = affinity_decay::run(&db).await {
tracing::error!(?err, "affinity decay run failed");
}
})
})?)
.await?;
}
scheduler.start().await?;
Ok(scheduler)
}