feat: add integrations

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2026-03-08 23:00:14 +01:00
parent 5a5f9a3003
commit 646581ff44
65 changed files with 7774 additions and 127 deletions

View File

@@ -0,0 +1,67 @@
use std::sync::Arc;
use std::time::Duration;
use forage_core::session::FileSessionStore;
use forage_db::PgSessionStore;
use notmad::{Component, ComponentInfo, MadError};
use tokio_util::sync::CancellationToken;
/// Session reaper for PostgreSQL-backed sessions.
pub struct PgSessionReaper {
pub store: Arc<PgSessionStore>,
pub max_inactive_days: i64,
}
impl Component for PgSessionReaper {
fn info(&self) -> ComponentInfo {
"forage/session-reaper-pg".into()
}
async fn run(&self, cancellation_token: CancellationToken) -> Result<(), MadError> {
let mut interval = tokio::time::interval(Duration::from_secs(300));
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
tokio::select! {
_ = cancellation_token.cancelled() => break,
_ = interval.tick() => {
match self.store.reap_expired(self.max_inactive_days).await {
Ok(n) if n > 0 => tracing::info!("session reaper: removed {n} expired sessions"),
Err(e) => tracing::warn!("session reaper error: {e}"),
_ => {}
}
}
}
}
Ok(())
}
}
/// Session reaper for file-backed sessions.
pub struct FileSessionReaper {
pub store: Arc<FileSessionStore>,
}
impl Component for FileSessionReaper {
fn info(&self) -> ComponentInfo {
"forage/session-reaper-file".into()
}
async fn run(&self, cancellation_token: CancellationToken) -> Result<(), MadError> {
let mut interval = tokio::time::interval(Duration::from_secs(300));
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
tokio::select! {
_ = cancellation_token.cancelled() => break,
_ = interval.tick() => {
self.store.reap_expired();
tracing::debug!("session reaper: {} active sessions", self.store.session_count());
}
}
}
Ok(())
}
}