refactor(job-registry): simplify the job registering*

This commit is contained in:
Edouard Vanbelle
2026-07-28 21:13:09 +02:00
parent 4d64603233
commit 0e8b1fbbeb
8 changed files with 224 additions and 126 deletions
@@ -3127,6 +3127,29 @@ impl DedupPort for DedupService {
/// and admin URLs (`POST /api/admin/jobs/dedup_gc/trigger`).
pub const DEDUP_GC_JOB_NAME: &str = "dedup_gc";
impl DedupService {
/// Register self with the periodic-job scheduler and return the
/// same `Arc<Self>` for DI-style chaining. **On-demand only** —
/// registered with `interval = None`. The periodic GC role
/// belongs to trash cleanup (which invokes `garbage_collect()`
/// inline as its tail step); a duplicate scheduled tick here
/// would double the reclamation work. Registration exists solely
/// to expose the admin trigger uniformly.
pub async fn register(
self: std::sync::Arc<Self>,
registry: &crate::infrastructure::scheduler::JobRegistry,
) -> std::sync::Arc<Self> {
registry
.register(
self.clone() as std::sync::Arc<dyn crate::infrastructure::scheduler::JobHandler>,
None, // on-demand
None, // no timeout
)
.await;
self
}
}
#[async_trait::async_trait]
impl crate::infrastructure::scheduler::JobHandler for DedupService {
fn name(&self) -> &str {
@@ -23,7 +23,7 @@ use tracing::{error, info};
use crate::application::ports::authorization_ports::AuthorizationEngine;
use crate::common::errors::DomainError;
use crate::infrastructure::scheduler::{JobHandler, JobOutcome, JobRunArgs};
use crate::infrastructure::scheduler::{JobHandler, JobOutcome, JobRegistry, JobRunArgs};
use crate::infrastructure::services::pg_acl_engine::PgAclEngine;
use async_trait::async_trait;
@@ -57,12 +57,22 @@ impl GrantCleanupService {
self.grace_days
}
/// Cadence exposed as `Duration` so DI passes a sanitised value
/// (post-`.max(1)`) to `JobRegistry::register`.
/// Cadence exposed as `Duration`. Internal helper used by
/// [`Self::register`]; kept `pub` for tests.
pub fn interval(&self) -> Duration {
Duration::from_secs(self.interval_hours * 3600)
}
/// Register self with the periodic-job scheduler and return the
/// same `Arc<Self>` for DI-style chaining. Scheduled tenant with
/// interval = `self.interval()`, no timeout. See
/// `docs/plan/job-registry.md` Part 1.
pub async fn register(self: Arc<Self>, registry: &JobRegistry) -> Arc<Self> {
let interval = self.interval();
registry.register(self.clone(), Some(interval), None).await;
self
}
/// Run one purge pass.
///
/// `grace_override`:
@@ -6,7 +6,7 @@ use tracing::{debug, error, info, instrument};
use crate::common::errors::Result;
use crate::domain::repositories::trash_repository::TrashRepository;
use crate::infrastructure::repositories::pg::trash_db_repository::TrashDbRepository;
use crate::infrastructure::scheduler::{JobHandler, JobOutcome, JobRunArgs};
use crate::infrastructure::scheduler::{JobHandler, JobOutcome, JobRegistry, JobRunArgs};
use crate::infrastructure::services::dedup_service::DedupService;
use async_trait::async_trait;
@@ -43,12 +43,31 @@ impl TrashCleanupService {
}
}
/// Registered interval as a `Duration` — helper for DI wiring so
/// the composition root doesn't reinvent the `hours × 3600` cast.
/// Registered interval as a `Duration`. Internal helper used by
/// [`Self::register`]; kept `pub` in case a test wants to assert
/// the clamped value.
pub fn interval(&self) -> Duration {
Duration::from_secs(self.cleanup_interval_hours * 3600)
}
/// Register self with the periodic-job scheduler and return the
/// same `Arc<Self>` for DI-style method chaining:
///
/// ```ignore
/// let svc = Arc::new(TrashCleanupService::new(...))
/// .register(&core.job_registry)
/// .await;
/// ```
///
/// Scheduled tenant — interval reads from
/// `self.cleanup_interval_hours`, no timeout. See
/// `docs/plan/job-registry.md` Part 1 §Contract.
pub async fn register(self: Arc<Self>, registry: &JobRegistry) -> Arc<Self> {
let interval = self.interval();
registry.register(self.clone(), Some(interval), None).await;
self
}
/// Starts the periodic cleanup job
#[instrument(skip(self))]
pub async fn start_cleanup_job(&self) {