//! Scheduled batch job example. //! //! Demonstrates running a data sync job on a schedule. The job runs to completion, //! then auto-restarts after a delay. Use `restart_on_success` for this pattern. use std::{future::Future, time::Duration}; use noprocess::{Process, ProcessHandler, ProcessManager, ProcessResult, ShutdownConfig}; use tokio_util::sync::CancellationToken; #[tokio::main] async fn main() -> Result<(), noprocess::Error> { tracing_subscriber::fmt::init(); let manager = ProcessManager::new(); // A batch job that runs every 2 seconds let sync_job = Process::builder(DataSyncJob) .handle_id("data-sync") .shutdown_config(ShutdownConfig { graceful_timeout: Duration::from_secs(10), restart_on_success: true, // Auto-restart after completion restart_delay: Duration::from_secs(2), // Wait 2s between runs }) .on_error(|e| eprintln!("Sync job failed: {e}")) .build(); let job_id = manager.add_process(sync_job).await; manager.start_process(&job_id).await?; println!("Batch job running (Ctrl+C to stop)...\n"); // Let it run a few cycles tokio::time::sleep(Duration::from_secs(10)).await; // Graceful shutdown - will wait for current batch to finish println!("\n--- Requesting graceful shutdown ---"); manager.stop_process(&job_id).await?; println!("Job stopped cleanly"); Ok(()) } struct DataSyncJob; impl ProcessHandler for DataSyncJob { fn call(&self, cancel: CancellationToken) -> impl Future + Send { async move { println!("[sync] Starting batch..."); // Simulate a batch job with multiple steps for step in 1..=3 { // Check for cancellation between steps if cancel.is_cancelled() { println!("[sync] Cancelled at step {step}, cleaning up..."); return Ok(()); } println!("[sync] Step {step}/3: processing..."); tokio::time::sleep(Duration::from_millis(300)).await; } println!("[sync] Batch complete!"); Ok(()) // Will auto-restart due to restart_on_success } } }