tiny-counter 0.1.0

Track event counts across time windows with fixed memory and fast queries
Documentation
// Async patterns and automatic persistence.
//
// This example shows how to:
// - Use EventStore with async/tokio runtime
// - Enable automatic background persistence
// - Handle graceful shutdown
// - Integrate with async workflows
//
// Run with: cargo run --example async_autopersist --features tokio,serde

#[cfg(not(feature = "tokio"))]
fn main() {
    println!("This example requires the 'tokio' feature.");
    println!("Run with: cargo run --example async_autopersist --features tokio,serde");
}

#[cfg(feature = "tokio")]
#[tokio::main(flavor = "current_thread")]
async fn main() {
    use chrono::Duration;
    use std::sync::Arc;
    use tiny_counter::storage::MemoryStorage;
    use tiny_counter::EventStore;

    println!("=== Async and Auto-Persist Examples ===\n");

    // 1. Auto-persistence with tokio
    println!("1. Auto-persistence (every 2 seconds):");
    {
        let store = Arc::new(
            EventStore::builder()
                .with_storage(MemoryStorage::new())
                .auto_persist(Duration::seconds(2))
                .build()
                .unwrap(),
        );

        println!("  Recording events...");

        // Record events continuously
        for i in 1..=5 {
            store.record("async_event");
            println!("  Recorded event {} (dirty: {})", i, store.is_dirty());
            tokio::time::sleep(tokio::time::Duration::from_millis(600)).await;
        }

        // Wait for auto-persist
        tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
        println!("  After auto-persist: dirty={}\n", store.is_dirty());
    }

    // 2. Async workflow integration
    println!("2. Async workflow integration:");
    {
        let store = Arc::new(EventStore::new());

        async fn process_request(store: Arc<EventStore>, request_id: u32) {
            store.record("async_request");

            // Simulate work
            tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;

            println!("  Processed request {}", request_id);
        }

        // Process multiple requests concurrently
        let mut tasks = vec![];
        for i in 0..5 {
            let store = Arc::clone(&store);
            tasks.push(tokio::spawn(process_request(store, i)));
        }

        // Wait for all tasks
        for task in tasks {
            task.await.unwrap();
        }

        let total = store.query("async_request").last_days(1).sum().unwrap_or(0);
        println!("  Total requests processed: {}\n", total);
    }

    // 3. Graceful shutdown
    println!("3. Graceful shutdown:");
    {
        let store = Arc::new(
            EventStore::builder()
                .with_storage(MemoryStorage::new())
                .auto_persist(Duration::seconds(10))
                .build()
                .unwrap(),
        );

        store.record("shutdown_event");
        store.record_count("shutdown_batch", 42);

        println!("  Recorded events");
        println!("  Is dirty: {}", store.is_dirty());

        // Explicit persist before shutdown
        store.persist().expect("Failed to persist");
        println!("  Explicitly persisted before shutdown");
        println!("  Is dirty: {}\n", store.is_dirty());
    }

    // 4. Concurrent async tasks
    println!("4. Concurrent async tasks:");
    {
        let store = Arc::new(EventStore::new());

        async fn analytics_task(store: Arc<EventStore>) {
            for i in 0..10 {
                store.record("analytics_tick");
                tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;

                if i % 3 == 0 {
                    let count = store
                        .query("analytics_tick")
                        .last_minutes(1)
                        .sum()
                        .unwrap_or(0);
                    println!("  Analytics: {} events so far", count);
                }
            }
        }

        async fn monitoring_task(store: Arc<EventStore>) {
            for _ in 0..5 {
                store.record("monitoring_check");
                tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
            }
            println!("  Monitoring: Completed checks");
        }

        // Run tasks concurrently
        tokio::join!(
            analytics_task(Arc::clone(&store)),
            monitoring_task(Arc::clone(&store)),
        );

        let analytics = store
            .query("analytics_tick")
            .last_days(1)
            .sum()
            .unwrap_or(0);
        let monitoring = store
            .query("monitoring_check")
            .last_days(1)
            .sum()
            .unwrap_or(0);

        println!(
            "  Final: {} analytics, {} monitoring\n",
            analytics, monitoring
        );
    }

    // 5. Rate limiting in async context
    println!("5. Async rate limiting:");
    {
        use tiny_counter::TimeUnit;
        let store = Arc::new(EventStore::new());

        async fn make_api_call(store: Arc<EventStore>, call_id: u32) -> Result<(), String> {
            // Check limit
            let result = store
                .limit()
                .at_most("async_api", 5, TimeUnit::Minutes)
                .check_and_record("async_api");

            match result {
                Ok(()) => {
                    // Simulate work
                    tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
                    println!("  API call {}: ✓ Success", call_id);
                    Ok(())
                }
                Err(e) => {
                    println!("  API call {}: ✗ Rate limited", call_id);
                    Err(format!("Rate limited: {}", e))
                }
            }
        }

        // Make rapid API calls
        for i in 0..8 {
            make_api_call(Arc::clone(&store), i).await.ok();
        }

        println!();
    }

    // 6. Background metrics collection
    println!("6. Background metrics collection:");
    {
        let store = Arc::new(EventStore::new());

        // Spawn background task
        let bg_store = Arc::clone(&store);
        let background_task = tokio::spawn(async move {
            for _ in 0..5 {
                bg_store.record("background_metric");
                tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
            }
            println!("  Background task: Collected metrics");
        });

        // Main task continues
        for _ in 0..3 {
            store.record("foreground_event");
            tokio::time::sleep(tokio::time::Duration::from_millis(150)).await;
        }
        println!("  Foreground: Processed events");

        // Wait for background task
        background_task.await.unwrap();

        let bg = store
            .query("background_metric")
            .last_days(1)
            .sum()
            .unwrap_or(0);
        let fg = store
            .query("foreground_event")
            .last_days(1)
            .sum()
            .unwrap_or(0);

        println!("  Total: {} background, {} foreground", bg, fg);
    }

    println!("\n✓ Async patterns complete!");
}