### Basic Oxanus Setup and Job Execution Source: https://github.com/pragmaplatform/oxanus/blob/main/oxanus/README.md This example demonstrates the basic setup for Oxanus, including defining a job, a worker, a queue, and the main execution flow. It shows how to initialize storage, build configuration, enqueue a job, and run the Oxanus worker. ```rust use oxanus::Storage; use serde::{Serialize, Deserialize}; #[derive(oxanus::Registry)] struct ComponentRegistry(oxanus::ComponentRegistry); #[derive(Debug, thiserror::Error)] enum MyError {} #[derive(Debug, Clone)] struct MyContext {} #[derive(Debug, Serialize, Deserialize)] struct MyJob { data: String, } #[derive(oxanus::Worker)] struct MyWorker; impl MyWorker { async fn process(&self, job: &MyJob, _ctx: &oxanus::JobContext) -> Result<(), MyError> { println!("Processing: {}", job.data); Ok(()) } } #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "my_queue", concurrency = 2)] struct MyQueue; #[tokio::main] async fn main() -> Result<(), oxanus::OxanusError> { let ctx = oxanus::ContextValue::new(MyContext {}); let storage = Storage::builder().build_from_env()?; let config = ComponentRegistry::build_config(&storage) .with_graceful_shutdown(tokio::signal::ctrl_c()); storage.enqueue(MyQueue, MyJob { data: "hello".into() }).await?; oxanus::run(config, ctx).await?; Ok(()) } ``` -------------------------------- ### Complete Oxanus Application Example Source: https://context7.com/pragmaplatform/oxanus/llms.txt This Rust code provides a comprehensive example of an Oxanus application. It includes setting up context, storage, and configuration, enqueuing jobs for order processing and notifications, and running workers with graceful shutdown. Ensure you have the necessary dependencies and environment variables configured. ```rust use serde::{Deserialize, Serialize}; use tracing_subscriber::{EnvFilter, fmt, prelude::*}; // Application context and error types #[derive(Debug, Clone)] struct AppContext { app_name: String, } #[derive(Debug, thiserror::Error)] enum AppError { #[error("Processing failed: {0}")] Failed(String), #[error("State error: {0}")] State(#[from] oxanus::OxanusError), } // Component registry with auto-discovery #[derive(oxanus::Registry)] struct ComponentRegistry(oxanus::ComponentRegistry); // Queue definitions #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "orders", concurrency = 5)] struct OrderQueue; #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "notifications", concurrency = 2)] #[oxanus(throttle(window_ms = 1000, limit = 10))] struct NotificationQueue; #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "cron")] struct CronQueue; // Order processing worker #[derive(Debug, Serialize, Deserialize)] struct ProcessOrderJob { order_id: i64, customer_id: i64, } #[derive(oxanus::Worker)] #[oxanus(max_retries = 3)] struct ProcessOrderWorker; impl ProcessOrderWorker { async fn process(&self, job: &ProcessOrderJob, _ctx: &oxanus::JobContext) -> Result<(), AppError> { tracing::info!("Processing order {} for customer {}", job.order_id, job.customer_id); tokio::time::sleep(std::time::Duration::from_millis(100)).await; Ok(()) } } // Notification worker with unique constraint #[derive(Debug, Serialize, Deserialize)] struct SendNotificationJob { user_id: i64, message: String, } #[derive(oxanus::Worker)] #[oxanus(unique_id = "notification:{user_id}", on_conflict = Skip)] struct SendNotificationWorker; impl SendNotificationWorker { async fn process(&self, job: &SendNotificationJob, _ctx: &oxanus::JobContext) -> Result<(), AppError> { tracing::info!("Sending notification to user {}: {}", job.user_id, job.message); Ok(()) } } // Cron worker for periodic cleanup #[derive(Debug, Serialize, Deserialize)] struct CleanupJob {} #[derive(oxanus::Worker)] #[oxanus(cron(schedule = "0 */5 * * * *", queue = CronQueue))] // Every 5 minutes struct CleanupWorker; impl CleanupWorker { async fn process(&self, _job: &CleanupJob, _ctx: &oxanus::JobContext) -> Result<(), AppError> { tracing::info!("Running periodic cleanup..."); Ok(()) } } #[tokio::main] async fn main() -> Result<(), Box> { // Initialize tracing tracing_subscriber::registry() .with(fmt::layer()) .with(EnvFilter::from_default_env()) .init(); // Create context let ctx = oxanus::ContextValue::new(AppContext { app_name: "my_service".to_string(), }); // Build storage let storage = oxanus::Storage::builder() .namespace("production") .build_from_env()?; // Build config with graceful shutdown let config = ComponentRegistry::build_config(&storage) .with_graceful_shutdown(tokio::signal::ctrl_c()); // Enqueue some initial jobs storage.enqueue(OrderQueue, ProcessOrderJob { order_id: 1001, customer_id: 42 }).await?; storage.enqueue(NotificationQueue, SendNotificationJob { user_id: 42, message: "Your order is confirmed!".into() }).await?; // Run workers (blocks until Ctrl+C) tracing::info!("Starting workers..."); let stats = oxanus::run(config, ctx).await?; tracing::info!( "Shutdown complete. Processed: {}, Succeeded: {}, Failed: {}", stats.processed, stats.succeeded, stats.failed ); Ok(()) } ``` -------------------------------- ### Prometheus Metrics Output Example Source: https://context7.com/pragmaplatform/oxanus/llms.txt Example output format for Prometheus metrics exported by Oxanus. ```text # HELP oxanus_jobs_total Total number of jobs (enqueued + scheduled) oxanus_jobs_total 100 # HELP oxanus_enqueued_total Total number of jobs currently enqueued oxanus_enqueued_total 50 # HELP oxanus_processed_total Total number of jobs processed oxanus_processed_total 200 # HELP oxanus_failed_total Total number of jobs failed oxanus_failed_total 10 # HELP oxanus_queue_enqueued Number of jobs enqueued per queue oxanus_queue_enqueued{queue="default"} 30 oxanus_queue_enqueued{queue="priority"} 20 # HELP oxanus_queue_latency_seconds Current latency per queue in seconds oxanus_queue_latency_seconds{queue="default"} 1.5 ``` -------------------------------- ### Run Oxanus Workers with Graceful Shutdown Source: https://context7.com/pragmaplatform/oxanus/llms.txt Use this function to start the worker system, processing jobs from registered queues. It supports graceful shutdown via a signal. ```rust use serde::{Deserialize, Serialize}; #[derive(oxanus::Registry)] struct ComponentRegistry(oxanus::ComponentRegistry); #[derive(Debug, thiserror::Error)] enum WorkerError {} #[derive(Debug, Clone)] struct WorkerContext { app_name: String, } #[derive(Debug, Serialize, Deserialize)] struct TaskJob { task_id: i64 } #[derive(oxanus::Worker)] struct TaskWorker; impl TaskWorker { async fn process(&self, job: &TaskJob, _ctx: &oxanus::JobContext) -> Result<(), WorkerError> { println!("Processing task {}", job.task_id); Ok(()) } } #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "tasks", concurrency = 4)] struct TaskQueue; #[tokio::main] async fn main() -> Result<(), oxanus::OxanusError> { // Create context shared across all workers let ctx = oxanus::ContextValue::new(WorkerContext { app_name: "my_app".to_string(), }); // Build storage and config let storage = oxanus::Storage::builder().build_from_env()?; let config = ComponentRegistry::build_config(&storage) .with_graceful_shutdown(tokio::signal::ctrl_c()); // Enqueue some jobs storage.enqueue(TaskQueue, TaskJob { task_id: 1 }).await?; storage.enqueue(TaskQueue, TaskJob { task_id: 2 }).await?; // Run workers (blocks until shutdown signal) let stats = oxanus::run(config, ctx).await?; println!("Processed {} jobs", stats.processed); Ok(()) } ``` -------------------------------- ### Rust: Unit struct worker example Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md A unit struct worker requires no application context and assumes the job type is named conventionally (e.g., MyJob for MyWorker). ```rust @derive(oxanus::Worker) struct MyWorker; // Assumes job type is `MyJob` ``` -------------------------------- ### Rust: Single-field struct worker example Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md A single-field worker struct automatically implements FromContext, cloning the field from the application context. ```rust @derive(oxanus::Worker) struct MyWorker { state: AppState, } // Assumes job type is `MyJob` ``` -------------------------------- ### Build Redis Storage from Environment Variable Source: https://context7.com/pragmaplatform/oxanus/llms.txt Configure and create a Redis connection using the `REDIS_URL` environment variable. This is the most common method for setting up storage. ```rust use oxanus::Storage; // Build from REDIS_URL environment variable (most common) let storage = Storage::builder().build_from_env()?; ``` -------------------------------- ### Generate Documentation with Cargo Source: https://github.com/pragmaplatform/oxanus/blob/main/CLAUDE.md Create project documentation using `cargo doc`. ```bash cargo doc ``` -------------------------------- ### Run Benchmarks with Cargo Source: https://github.com/pragmaplatform/oxanus/blob/main/CLAUDE.md Execute benchmarks using the `divan` framework with `cargo bench`. ```bash cargo bench ``` -------------------------------- ### Perform Quick Syntax Check Source: https://github.com/pragmaplatform/oxanus/blob/main/CLAUDE.md Use `cargo check --all` for a fast syntax and type check without performing a full build. ```bash cargo check --all ``` -------------------------------- ### Format Codebase with Cargo Source: https://github.com/pragmaplatform/oxanus/blob/main/CLAUDE.md Apply code formatting across the entire workspace using `cargo fmt --workspace`. ```bash cargo fmt --workspace ``` -------------------------------- ### Build Project with Cargo Source: https://github.com/pragmaplatform/oxanus/blob/main/CLAUDE.md Use `cargo build` to compile the project. This command builds all crates within the workspace. ```bash cargo build ``` -------------------------------- ### Build Redis Storage from Explicit URL Source: https://context7.com/pragmaplatform/oxanus/llms.txt Establish a Redis connection by providing an explicit connection URL to the `StorageBuilder`. ```rust // Build from explicit Redis URL let storage = Storage::builder() .build_from_redis_url("redis://localhost:6379")?; ``` -------------------------------- ### Run Linter with Cargo Source: https://github.com/pragmaplatform/oxanus/blob/main/CLAUDE.md Enforce code quality by running the Rust linter with extensive warnings enabled via `cargo clippy --all-features --workspace`. ```bash cargo clippy --all-features --workspace ``` -------------------------------- ### Register Cron Worker (After) Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md Demonstrates the new approach to registering cron workers using attributes and `register_worker`. ```rust #[derive(oxanus::Worker)] #[oxanus(job = MyCronJob)] #[oxanus(cron(schedule = "*/5 * * * * *", queue = MyQueue))] struct MyCronWorker; let config = oxanus::Config::new(&storage) .register_worker::(); ``` -------------------------------- ### Add Oxanus Dependency Source: https://github.com/pragmaplatform/oxanus/blob/main/oxanus/README.md Add the oxanus crate to your Cargo.toml file to include it in your project. ```bash cargo add oxanus ``` -------------------------------- ### Run All Tests with Cargo Source: https://github.com/pragmaplatform/oxanus/blob/main/CLAUDE.md Execute all unit and integration tests using `cargo test`. For specific tests, append the test name. ```bash cargo test ``` ```bash cargo test ``` -------------------------------- ### Build Redis Storage with Custom Pool Size and Timeouts Source: https://context7.com/pragmaplatform/oxanus/llms.txt Configure advanced Redis connection settings, including the maximum connection pool size and request timeouts, for fine-grained control over performance and reliability. ```rust // Build with custom pool size and timeouts use oxanus::StorageBuilderTimeouts; let storage = Storage::builder() .namespace("production") .max_pool_size(100) .timeouts(StorageBuilderTimeouts::new(std::time::Duration::from_millis(500))) .build_from_redis_url("redis://localhost:6379")?; ``` -------------------------------- ### Register Cron Worker (Before) Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md Shows the previous method of registering a cron worker using `register_cron_worker`. ```rust let config = oxanus::Config::new(&storage) .register_cron_worker::(MyDynamicQueue(1)); ``` -------------------------------- ### Run All Tests with Cargo Source: https://github.com/pragmaplatform/oxanus/blob/main/AGENTS.md Executes all unit and integration tests within the project. ```bash cargo test ``` -------------------------------- ### Rust: Implement FromContext for worker Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md For complex worker initialization, manually implement the FromContext trait to provide application state to the worker. ```rust impl oxanus::FromContext for MyWorker { fn from_context(ctx: &AppState) -> Self { Self { db: ctx.db_pool.clone(), mailer: ctx.mailer.clone(), } } } ``` -------------------------------- ### Enqueue Jobs Immediately with Oxanus Source: https://context7.com/pragmaplatform/oxanus/llms.txt Use `storage.enqueue()` to add a job to a queue for immediate processing. The job must implement `Serialize` and `Deserialize`. ```rust use chrono::{Duration, Utc}; use oxanus::Storage; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] struct NotificationJob { user_id: i64, message: String, } #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "notifications")] struct NotificationQueue; async fn enqueue_examples(storage: &Storage) -> Result<(), oxanus::OxanusError> { // Enqueue for immediate processing let job_id = storage.enqueue( NotificationQueue, NotificationJob { user_id: 1, message: "Welcome!".into() } ).await?; println!("Enqueued job: {}", job_id); ``` -------------------------------- ### Rust: Update context creation (0.9 vs 0.10) Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md Context creation changes from `oxanus::Context::value` in 0.9 to `oxanus::ContextValue::new` in 0.10. ```rust // Before: let ctx = oxanus::Context::value(AppState { db, mailer }); ``` ```rust // After: let ctx = oxanus::ContextValue::new(AppState { db, mailer }); ``` -------------------------------- ### Define Static Queues with Oxanus Source: https://context7.com/pragmaplatform/oxanus/llms.txt Use `#[derive(oxanus::Queue)]` to define static queues. Specify concurrency and throttling options as needed. ```rust use serde::Serialize; // Static queue with default concurrency (1) #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "emails")] struct EmailQueue; // Static queue with custom concurrency #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "imports", concurrency = 5)] struct ImportQueue; // Queue with throttling (rate limiting) // Limit: 10 jobs per 5000ms window #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "api_calls", concurrency = 3)] #[oxanus(throttle(window_ms = 5000, limit = 10))] struct ApiCallQueue; ``` -------------------------------- ### Enable Prometheus Metrics in Oxanus Source: https://github.com/pragmaplatform/oxanus/blob/main/oxanus/README.md To expose Prometheus metrics, enable the 'prometheus' feature. This snippet shows how to retrieve and encode metrics from the storage. ```rust let metrics = storage.metrics().await?; let output = metrics.encode_to_string()?; // Serve `output` on your metrics endpoint ``` -------------------------------- ### Integrate Oxanus Web Dashboard with Axum Source: https://github.com/pragmaplatform/oxanus/blob/main/oxanus/README.md This snippet shows how to integrate the Oxanus web dashboard into an existing Axum application. It demonstrates creating the Oxanus router and nesting it within your main application router. ```rust use oxanus_web::OxanusWebState; let config = ComponentRegistry::build_config(&storage) .with_graceful_shutdown(tokio::signal::ctrl_c()); let oxanus_router = oxanus_web::router(OxanusWebState::new( config.storage.clone(), config.catalog(), "/oxanus".to_string(), )); let app = your_app_router().nest("/oxanus", oxanus_router); ``` -------------------------------- ### Monitor Storage Statistics with Oxanus Source: https://context7.com/pragmaplatform/oxanus/llms.txt Use the Storage API to retrieve global and per-queue statistics, including job counts, enqueued, processed, failed, dead, scheduled, and retries. This is useful for understanding the overall health and load of your job processing system. ```rust use oxanus::{Storage, QueueListOpts}; async fn monitoring_examples(storage: &Storage) -> Result<(), oxanus::OxanusError> { // Get full statistics let stats = storage.stats().await?; println!("Total jobs: {}", stats.global.jobs); println!("Enqueued: {}", stats.global.enqueued); println!("Processed: {}", stats.global.processed); println!("Failed: {}", stats.global.failed); println!("Dead: {}", stats.global.dead); println!("Scheduled: {}", stats.global.scheduled); println!("Retries: {}", stats.global.retries); // Per-queue statistics for queue_stats in &stats.queues { println!("Queue {}: {} enqueued, {} processed", queue_stats.key, queue_stats.enqueued, queue_stats.processed); } // Get specific queue stats by pattern let email_stats = storage.stats_queues_for(&["email*"]).await?; // Count jobs in a specific queue #[derive(serde::Serialize, oxanus::Queue)] #[oxanus(key = "tasks")] struct TaskQueue; let count = storage.enqueued_count(TaskQueue).await?; println!("Tasks queue has {} jobs", count); // Get queue latency (age of oldest job) let latency_ms = storage.latency_ms(TaskQueue).await?; println!("Queue latency: {}ms", latency_ms); // List jobs with pagination let opts = QueueListOpts { count: 20, offset: 0 }; let jobs = storage.list_queue_jobs(TaskQueue, &opts).await?; for job in jobs { println!("Job {}: {} (retries: {})", job.id, job.job.name, job.meta.retries); } // List dead jobs let dead_jobs = storage.list_dead(&opts).await?; println!("Dead jobs: {}", dead_jobs.len()); // List scheduled jobs let scheduled = storage.list_scheduled(&opts).await?; println!("Scheduled jobs: {}", scheduled.len()); // List jobs pending retry let retries = storage.list_retries(&opts).await?; println!("Retrying jobs: {}", retries.len()); // Delete a specific job if let Some(job) = jobs.first() { storage.delete_job(&job.id).await?; } // Wipe entire queue storage.wipe_queue(TaskQueue).await?; // List active worker processes let processes = storage.processes().await?; for process in processes { println!("Process {} on {}", process.pid, process.hostname); } Ok(()) } ``` -------------------------------- ### Component Registry Auto-discovery Source: https://context7.com/pragmaplatform/oxanus/llms.txt Use `#[derive(oxanus::Registry)]` to automatically discover and register workers and queues. Define context and error types for your application. ```rust use serde::{Deserialize, Serialize}; // Define context type shared across workers #[derive(Debug, Clone)] struct AppContext { db_pool: DatabasePool, api_client: ApiClient, } // Define error type for workers #[derive(Debug, thiserror::Error)] enum AppError { #[error("Database error: {0}")] DbError(String), #[error("API error: {0}")] ApiError(String), } // Create the registry - this auto-discovers all workers and queues #[derive(oxanus::Registry)] struct ComponentRegistry(oxanus::ComponentRegistry); // Define workers (automatically registered) #[derive(Debug, Serialize, Deserialize)] struct ProcessOrderJob { order_id: i64 } #[derive(oxanus::Worker)] struct ProcessOrderWorker; impl ProcessOrderWorker { async fn process(&self, job: &ProcessOrderJob, _ctx: &oxanus::JobContext) -> Result<(), AppError> { Ok(()) } } // Define queues (automatically registered) #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "orders", concurrency = 10)] struct OrderQueue; // Build config from registry fn main() -> Result<(), oxanus::OxanusError> { let storage = oxanus::Storage::builder().build_from_env()?; // Auto-registers all workers and queues defined with macros let config = ComponentRegistry::build_config(&storage) .with_graceful_shutdown(tokio::signal::ctrl_c()); // Verify registration assert!(config.has_registered_queue::()); assert!(config.has_registered_worker("ProcessOrderJob")); Ok(()) } ``` -------------------------------- ### Configure Throttled Queues for Rate Limiting in Rust Source: https://context7.com/pragmaplatform/oxanus/llms.txt Set up queues with throttling to control job processing rates, essential for managing external API limits or resource constraints. Jobs can also have custom throttle costs. ```rust use serde::{Deserialize, Serialize}; #[derive(oxanus::Registry)] struct ComponentRegistry(oxanus::ComponentRegistry<(), WorkerError>); #[derive(Debug, thiserror::Error)] enum WorkerError {} // Throttled queue: max 5 jobs per 2000ms (2.5 jobs/second) #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "api_calls", concurrency = 2)] #[oxanus(throttle(window_ms = 2000, limit = 5))] struct ApiCallQueue; #[derive(Debug, Serialize, Deserialize)] struct ApiCallJob { endpoint: String, } #[derive(oxanus::Worker)] struct ApiCallWorker; impl ApiCallWorker { async fn process(&self, job: &ApiCallJob, _ctx: &oxanus::JobContext) -> Result<(), WorkerError> { println!("Calling API: {}", job.endpoint); Ok(()) } } // Jobs with custom throttle cost (counts as multiple jobs against the limit) #[derive(Debug, Serialize, Deserialize)] struct HeavyApiCallJob { endpoint: String, } #[derive(oxanus::Worker)] #[oxanus(throttle_cost = 3)] // This job counts as 3 against the throttle limit struct HeavyApiCallWorker; impl HeavyApiCallWorker { async fn process(&self, job: &HeavyApiCallJob, _ctx: &oxanus::JobContext) -> Result<(), WorkerError> { println!("Heavy API call: {}", job.endpoint); Ok(()) } } #[tokio::main] async fn main() -> Result<(), oxanus::OxanusError> { let ctx = oxanus::ContextValue::new(()); let storage = oxanus::Storage::builder().build_from_env()?; let config = ComponentRegistry::build_config(&storage).exit_when_processed(10); // Enqueue many jobs - they will be rate limited for i in 0..10 { storage.enqueue(ApiCallQueue, ApiCallJob { endpoint: format!("/api/resource/{}", i) }).await?; } oxanus::run(config, ctx).await?; Ok(()) } ``` -------------------------------- ### Manual Worker Trait Implementations Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md Illustrates the three required trait implementations for manual `Worker` trait implementations: `Job`, `Worker`, and `FromContext`. ```rust // 1. Job trait on the job data struct impl oxanus::Job for MyJob { fn worker_name() -> &'static str { std::any::type_name::() } // Optional: unique_id, on_conflict, should_resurrect, throttle_cost } ``` ```rust // 2. Worker trait on the worker struct (now generic over job type) #[async_trait::async_trait] impl oxanus::Worker for MyWorker { type Error = MyError; async fn process(&self, job: &MyJob, ctx: &oxanus::JobContext) -> Result<(), MyError> { // ... Ok(()) } // Optional: max_retries, retry_delay, cron_schedule, cron_queue_config } ``` ```rust // 3. FromContext trait for constructing the worker from app context impl oxanus::FromContext for MyWorker { fn from_context(ctx: &AppState) -> Self { Self { state: ctx.clone() } } } ``` -------------------------------- ### Define Dynamic Queues with Oxanus Source: https://context7.com/pragmaplatform/oxanus/llms.txt Define dynamic queues using `#[oxanus(prefix = ...)]` and struct fields. These create queues based on runtime values. ```rust // Dynamic queue - creates separate queues per tenant #[derive(Serialize, oxanus::Queue)] #[oxanus(prefix = "tenant", concurrency = 2)] struct TenantQueue { tenant_id: i64, } // Usage: TenantQueue { tenant_id: 123 } creates queue "tenant#tenant_id=123" // Dynamic queue with multiple fields #[derive(Serialize, oxanus::Queue)] #[oxanus(prefix = "region", concurrency = 4)] struct RegionPriorityQueue { region: String, priority: u8, } // Creates queues like "region#region=us-east:priority=1" ``` -------------------------------- ### Build Redis Storage with Custom Namespace Source: https://context7.com/pragmaplatform/oxanus/llms.txt Isolate your jobs within Redis by specifying a custom namespace during storage configuration. This prevents key collisions with other Redis applications. ```rust // Build with custom namespace (isolates jobs in Redis) let storage = Storage::builder() .namespace("myapp") .build_from_env()?; ``` -------------------------------- ### Rust: Update config registration (0.9 vs 0.10) Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md Registering workers in the config changes from `register_worker::()` to `register_worker::()`, specifying both worker and job types. ```rust // Before: let config = oxanus::Config::new(&storage) .register_queue::() .register_worker::(); ``` ```rust // After: let config = oxanus::Config::new(&storage) .register_queue::() .register_worker::(); ``` -------------------------------- ### Run Specific Test with Cargo Source: https://github.com/pragmaplatform/oxanus/blob/main/AGENTS.md Allows running a single test by its name. ```bash cargo test ``` -------------------------------- ### Enqueue Jobs at a Specific Time using Oxanus Source: https://context7.com/pragmaplatform/oxanus/llms.txt Use `storage.enqueue_at()` to schedule a job for processing at a specific `chrono::DateTime`. ```rust // Enqueue at specific time let scheduled_time = Utc::now() + Duration::hours(1); let job_id = storage.enqueue_at( NotificationQueue, NotificationJob { user_id: 3, message: "Scheduled".into() }, scheduled_time ).await?; println!("Scheduled job at {}: {}", scheduled_time, job_id); ``` -------------------------------- ### Implement Resumable Jobs with State Persistence in Rust Source: https://context7.com/pragmaplatform/oxanus/llms.txt Define job state structures and worker logic to save and restore progress across retries. Ensure state is updated before potential failures. ```rust use serde::{Deserialize, Serialize}; use oxanus::{JobContext, OxanusError}; #[derive(Debug, thiserror::Error)] enum WorkerError { #[error("Step failed: {0}")] StepFailed(String), #[error("State error: {0}")] StateError(#[from] OxanusError), } // Job state that persists across retries #[derive(Debug, Serialize, Deserialize)] struct MigrationProgress { processed_records: usize, last_processed_id: Option, } #[derive(Debug, Serialize, Deserialize)] struct DataMigrationJob { batch_size: usize, total_records: usize, } #[derive(oxanus::Worker)] #[oxanus(max_retries = 10, retry_delay = 5)] struct DataMigrationWorker; impl DataMigrationWorker { async fn process(&self, job: &DataMigrationJob, ctx: &JobContext) -> Result<(), WorkerError> { // Restore progress from previous attempt (if any) let mut progress: MigrationProgress = ctx.state .get() .await? .unwrap_or(MigrationProgress { processed_records: 0, last_processed_id: None, }); println!("Resuming from record {}", progress.processed_records); // Process records in batches while progress.processed_records < job.total_records { // Simulate processing a batch let batch_end = (progress.processed_records + job.batch_size).min(job.total_records); // Simulate potential failure if progress.processed_records == 50 && progress.last_processed_id.is_none() { // Save progress before failing progress.last_processed_id = Some(50); ctx.state.update(&progress).await?; return Err(WorkerError::StepFailed("Network error".into())); } progress.processed_records = batch_end; progress.last_processed_id = Some(batch_end as i64); // Persist progress after each batch ctx.state.update(&progress).await?; println!("Processed {} / {} records", progress.processed_records, job.total_records); } println!("Migration complete!"); Ok(()) } } ``` -------------------------------- ### Enqueue Jobs to Dynamic Queues with Oxanus Source: https://context7.com/pragmaplatform/oxanus/llms.txt Enqueue jobs to dynamically created queues by defining a queue struct with a prefix and fields. ```rust // Enqueue to dynamic queue #[derive(Serialize, oxanus::Queue)] #[oxanus(prefix = "user_notifications")] struct UserNotificationQueue { user_id: i64 } storage.enqueue( UserNotificationQueue { user_id: 42 }, NotificationJob { user_id: 42, message: "Personal".into() } ).await?; ``` -------------------------------- ### Define Basic Email Worker Source: https://context7.com/pragmaplatform/oxanus/llms.txt Implement a basic worker for processing `EmailJob` with default retry settings (2 retries, exponential backoff). Ensure your job data is `Serialize` and `Deserialize`. ```rust use serde::{Deserialize, Serialize}; use oxanus::JobContext; // Define your application's error type #[derive(Debug, thiserror::Error)] enum WorkerError { #[error("Processing failed: {0}")] ProcessingFailed(String), } // Basic worker with default settings (2 retries, exponential backoff) #[derive(Debug, Serialize, Deserialize)] struct EmailJob { to: String, subject: String, body: String, } #[derive(oxanus::Worker)] struct EmailWorker; impl EmailWorker { async fn process(&self, job: &EmailJob, _ctx: &JobContext) -> Result<(), WorkerError> { println!("Sending email to {}: {}", job.to, job.subject); // Send email logic here Ok(()) } } ``` -------------------------------- ### Enqueue Jobs with Delay using Oxanus Source: https://context7.com/pragmaplatform/oxanus/llms.txt Use `storage.enqueue_in()` to schedule a job for processing after a specified delay in seconds. ```rust // Enqueue with delay (in seconds) // Job will be processed after 300 seconds (5 minutes) let job_id = storage.enqueue_in( NotificationQueue, NotificationJob { user_id: 2, message: "Reminder".into() }, 300 // delay in seconds ).await?; println!("Scheduled job with delay: {}", job_id); ``` -------------------------------- ### Export Prometheus Metrics Source: https://context7.com/pragmaplatform/oxanus/llms.txt Enable the `prometheus` feature in Cargo.toml to export metrics. This function retrieves and encodes metrics into Prometheus text format. ```rust use oxanus::Storage; // In Cargo.toml: oxanus = { version = "1.0", features = ["prometheus"] } async fn metrics_endpoint(storage: &Storage) -> Result { // Get metrics from current stats let metrics = storage.metrics().await?; // Encode to Prometheus text format let output = metrics.encode_to_string() .map_err(|e| oxanus::OxanusError::GenericError(e.to_string()))?; Ok(output) } ``` ```rust // Example Axum handler async fn prometheus_handler( axum::extract::Extension(storage): axum::extract::Extension, ) -> impl axum::response::IntoResponse { match storage.metrics().await { Ok(metrics) => { match metrics.encode_to_string() { Ok(output) => ( axum::http::StatusCode::OK, [("content-type", "text/plain; charset=utf-8")], output ), Err(e) => ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, [("content-type", "text/plain; charset=utf-8")], format!("Encoding error: {}", e) ), } } Err(e) => ( axum::http::StatusCode::INTERNAL_SERVER_ERROR, [("content-type", "text/plain; charset=utf-8")], format!("Stats error: {}", e) ), } } ``` -------------------------------- ### Rust: Define SendEmail job and worker (0.10) Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md After migration, split SendEmail into SendEmailJob (data) and SendEmail (worker logic). The worker struct derives oxanus::Worker and holds application state. ```rust // Job struct — holds the serialized data #[derive(Debug, Serialize, Deserialize)] struct SendEmailJob { user_id: i64, subject: String, body: String, } // Worker struct — holds processing logic (and optionally app context) #[derive(oxanus::Worker)] #[oxanus(unique_id = "send_email:{user_id}")] #[oxanus(max_retries = 3)] struct SendEmail { state: AppState, // single field → auto FromContext } impl SendEmail { async fn process(&self, job: &SendEmailJob, _ctx: &oxanus::JobContext) -> Result<(), AppError> { self.state.mailer.send(job.user_id, &job.subject, &job.body).await?; Ok(()) } } ``` -------------------------------- ### Rust: Define SendEmail worker (0.9) Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md Before migration, the SendEmail struct combined job data and worker logic, deriving oxanus::Worker. ```rust #[derive(Debug, Serialize, Deserialize, oxanus::Worker)] #[oxanus(unique_id = "send_email:{user_id}")] #[oxanus(max_retries = 3)] struct SendEmail { user_id: i64, subject: String, body: String, } impl SendEmail { async fn process(&self, ctx: &oxanus::Context) -> Result<(), AppError> { let mailer = &ctx.ctx.mailer; mailer.send(self.user_id, &self.subject, &self.body).await?; Ok(()) } } ``` -------------------------------- ### Define Worker with Custom Retry Settings Source: https://context7.com/pragmaplatform/oxanus/llms.txt Configure a worker with custom retry counts and delay intervals using the `#[oxanus(max_retries = ..., retry_delay = ...)]` attributes. This allows tailoring retry behavior to specific job needs. ```rust // Worker with custom retry settings #[derive(Debug, Serialize, Deserialize)] struct ImportJob { file_path: String, } #[derive(oxanus::Worker)] #[oxanus(max_retries = 5, retry_delay = 60)] // 5 retries, 60 second delay struct ImportWorker; impl ImportWorker { async fn process(&self, job: &ImportJob, _ctx: &JobContext) -> Result<(), WorkerError> { println!("Importing file: {}", job.file_path); Ok(()) } } ``` -------------------------------- ### Confirm Queue Wipe Source: https://github.com/pragmaplatform/oxanus/blob/main/oxanus-web/templates/queue_detail.html JavaScript function to confirm wiping a queue by prompting the user to type the queue name. Use this before initiating a queue wipe operation. ```javascript function confirmWipe(queueKey) { var input = prompt('Type the queue name to confirm wipe: ' + queueKey); return input === queueKey; } ``` -------------------------------- ### Define Cron Workers for Periodic Job Scheduling Source: https://context7.com/pragmaplatform/oxanus/llms.txt Use the `cron` attribute to define workers that run on a schedule. Cron expressions use 6 parts: seconds, minutes, hours, day of month, month, day of week. Workers are automatically scheduled and do not require manual enqueueing. ```rust use serde::{Deserialize, Serialize}; #[derive(oxanus::Registry)] struct ComponentRegistry(oxanus::ComponentRegistry<(), WorkerError>); #[derive(Debug, thiserror::Error)] enum WorkerError {} // Queue for cron jobs #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "cron_jobs")] struct CronQueue; // Cron job that runs every 5 seconds #[derive(Debug, Serialize, Deserialize)] struct HealthCheckJob {} #[derive(oxanus::Worker)] #[oxanus(cron(schedule = "*/5 * * * * *", queue = CronQueue))] #[oxanus(resurrect = false)] // Don't resurrect if worker crashes mid-job struct HealthCheckWorker; impl HealthCheckWorker { async fn process(&self, _job: &HealthCheckJob, _ctx: &oxanus::JobContext) -> Result<(), WorkerError> { println!("Health check at {:?}", chrono::Utc::now()); Ok(()) } } // Cron job that runs every minute #[derive(Debug, Serialize, Deserialize)] struct MetricsCollectorJob {} #[derive(oxanus::Worker)] #[oxanus(cron(schedule = "0 * * * * *", queue = CronQueue))] // Every minute at :00 struct MetricsCollectorWorker; impl MetricsCollectorWorker { async fn process(&self, _job: &MetricsCollectorJob, _ctx: &oxanus::JobContext) -> Result<(), WorkerError> { println!("Collecting metrics..."); Ok(()) } } // Cron job that runs daily at midnight #[derive(Debug, Serialize, Deserialize)] struct DailyReportJob {} #[derive(oxanus::Worker)] #[oxanus(cron(schedule = "0 0 0 * * *", queue = CronQueue))] // Every day at 00:00:00 struct DailyReportWorker; impl DailyReportWorker { async fn process(&self, _job: &DailyReportJob, _ctx: &oxanus::JobContext) -> Result<(), WorkerError> { println!("Generating daily report..."); Ok(()) } } #[tokio::main] async fn main() -> Result<(), oxanus::OxanusError> { let ctx = oxanus::ContextValue::new(()); let storage = oxanus::Storage::builder().build_from_env()?; let config = ComponentRegistry::build_config(&storage) .with_graceful_shutdown(tokio::signal::ctrl_c()); // Cron workers are automatically scheduled - no manual enqueueing needed oxanus::run(config, ctx).await?; Ok(()) } ``` -------------------------------- ### Synchronous Job Draining for Testing Source: https://context7.com/pragmaplatform/oxanus/llms.txt The `drain` function processes all jobs in a queue synchronously. This is useful for testing and development environments. Ensure `serde` and `thiserror` are added as dependencies. ```rust use serde::{Deserialize, Serialize}; #[derive(oxanus::Registry)] struct ComponentRegistry(oxanus::ComponentRegistry<(), WorkerError>); #[derive(Debug, thiserror::Error)] enum WorkerError {} #[derive(Debug, Serialize, Deserialize)] struct TestJob { value: i32 } #[derive(oxanus::Worker)] struct TestWorker; impl TestWorker { async fn process(&self, job: &TestJob, _ctx: &oxanus::JobContext) -> Result<(), WorkerError> { println!("Processing: {}", job.value); Ok(()) } } #[derive(Serialize, oxanus::Queue)] #[oxanus(key = "test")] struct TestQueue; #[tokio::test] async fn test_job_processing() -> Result<(), oxanus::OxanusError> { let storage = oxanus::Storage::builder() .namespace("test") .build_from_env()?; let config = ComponentRegistry::build_config(&storage); let ctx = oxanus::ContextValue::new(()) // Enqueue test jobs storage.enqueue(TestQueue, TestJob { value: 1 }).await?; storage.enqueue(TestQueue, TestJob { value: 2 }).await?; storage.enqueue(TestQueue, TestJob { value: 3 }).await?; // Drain the queue (process all jobs synchronously) let stats = oxanus::drain(&config, ctx, TestQueue).await?; println!("Processed: {}", stats.processed); println!("Succeeded: {}", stats.succeeded); println!("Failed: {}", stats.failed); assert_eq!(stats.processed, 3); assert_eq!(stats.succeeded, 3); assert_eq!(stats.failed, 0); Ok(()) } ``` -------------------------------- ### Rust: Update enqueue calls (0.9 vs 0.10) Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md Enqueue calls now take the job struct (e.g., SendEmailJob) instead of the worker struct. ```rust // Before: storage.enqueue(MyQueue, SendEmail { user_id: 1, subject: "hi".into(), body: "hello".into() }).await?; ``` ```rust // After: storage.enqueue(MyQueue, SendEmailJob { user_id: 1, subject: "hi".into(), body: "hello".into() }).await?; ``` -------------------------------- ### Define Unique Worker with Replace Conflict Resolution Source: https://context7.com/pragmaplatform/oxanus/llms.txt Configure a unique worker to replace existing jobs if a duplicate is detected, using `on_conflict = Replace`. This is suitable for scenarios where the latest job data should always take precedence. ```rust // Replace existing job on conflict #[derive(Debug, Serialize, Deserialize)] struct CacheRefreshJob { cache_key: String, } #[derive(oxanus::Worker)] #[oxanus(unique_id = "cache:{cache_key}", on_conflict = Replace)] struct CacheRefreshWorker; impl CacheRefreshWorker { async fn process(&self, job: &CacheRefreshJob, _ctx: &JobContext) -> Result<(), WorkerError> { println!("Refreshing cache: {}", job.cache_key); Ok(()) } } ``` -------------------------------- ### Define Unique Worker with Skip Conflict Resolution Source: https://context7.com/pragmaplatform/oxanus/llms.txt Implement a unique worker that prevents duplicate jobs by using a unique ID pattern and specifying `on_conflict = Skip`. This is useful for idempotent operations where duplicates should be ignored. ```rust // Unique worker - prevents duplicate jobs with same ID #[derive(Debug, Serialize, Deserialize)] struct UserSyncJob { user_id: i64, } #[derive(oxanus::Worker)] #[oxanus(unique_id = "user_sync:{user_id}", on_conflict = Skip)] // Skip duplicates struct UserSyncWorker; impl UserSyncWorker { async fn process(&self, job: &UserSyncJob, _ctx: &JobContext) -> Result<(), WorkerError> { println!("Syncing user {}", job.user_id); Ok(()) } } ``` -------------------------------- ### Confirm Job Deletion Source: https://github.com/pragmaplatform/oxanus/blob/main/oxanus-web/templates/queue_detail.html JavaScript function to confirm the deletion of a specific job. It displays a confirmation dialog to the user. Use this before deleting a job. ```javascript function confirmDeleteJob(jobId) { return confirm('Are you sure you want to delete job ' + jobId + '?'); } ``` -------------------------------- ### Toggle Full Error Display Source: https://github.com/pragmaplatform/oxanus/blob/main/oxanus-web/templates/global_jobs.html JavaScript function to toggle the visibility of truncated and full error messages. Call this function when the 'View full error' button is clicked. ```javascript function toggleFullError(btn) { var container = btn.parentElement; var truncated = container.querySelector('.error-truncated'); var full = container.querySelector('.error-full'); if (full.style.display === 'none') { truncated.style.display = 'none'; full.style.display = ''; btn.textContent = 'Show less'; } else { truncated.style.display = ''; full.style.display = 'none'; btn.textContent = 'View full error'; } } ``` -------------------------------- ### Copy Error Information Source: https://github.com/pragmaplatform/oxanus/blob/main/oxanus-web/templates/global_jobs.html JavaScript function to copy job error details to the clipboard. This function uses the Clipboard API and provides user feedback on success or failure. It requires data attributes on the button to be set. ```javascript function copyErrorInfo(btn) { var info = [ 'Job: ' + btn.dataset.jobName, 'Queue: ' + btn.dataset.queue, 'Created: ' + btn.dataset.created, 'Arguments: ' + btn.dataset.args, 'Error: ' + btn.dataset.error ].join('\n'); navigator.clipboard.writeText(info).then(function() { btn.textContent = 'Copied!'; setTimeout(function() { btn.textContent = 'Copy Error Info'; }, 1500); }, function() { btn.textContent = 'Copy failed'; setTimeout(function() { btn.textContent = 'Copy Error Info'; }, 1500); }); } ``` -------------------------------- ### Rust: Update has_registered_worker checks (0.9 vs 0.10) Source: https://github.com/pragmaplatform/oxanus/blob/main/MIGRATION.md Methods like `has_registered_worker` are updated to `has_registered_worker_type` to reflect the new worker/job separation. ```rust // Before: config.has_registered_worker::() config.has_registered_cron_worker::() ``` ```rust // After: config.has_registered_worker_type::() config.has_registered_cron_worker_type::() ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.