Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Diagnostics and Events

Use diagnostics to prove cache behavior locally before adding more infrastructure. The simplest useful check is: call the same cached operation twice, then inspect hit, load, and request counters.

    let cache = HydraCache::local().build();

    let first = cacheable_infallible!(
        cache = cache,
        key = "expensive:42",
        tags = ["expensive"],
        ttl_secs = 60,
        load = || async { 42_u64 },
    )
    .await?;

    let second = cacheable_infallible!(
        cache = cache,
        key = "expensive:42",
        tags = ["expensive"],
        ttl_secs = 60,
        load = || async { 7_u64 },
    )
    .await?;

    let diagnostics = cache.diagnostics().await;

    assert_eq!((first, second), (42, 42));
    assert_eq!(diagnostics.stats.loads, 1);
    assert_eq!(diagnostics.stats.hits, 1);
    assert_eq!(diagnostics.total_requests(), 2);
    assert_eq!(diagnostics.hit_ratio(), Some(0.5));
    assert!(!diagnostics.is_empty());

The first call misses and runs the loader. The second call hits the cache and avoids the fallback loader value.

Event Streams

Use event streams when an application needs to observe cache behavior without wrapping every cache call manually.

    let cache = HydraCache::local().build();
    let mut events = cache.subscribe_tag("users");

    cache
        .put("user:42", 42_u64, CacheOptions::new().tag("users"))
        .await?;

    let event = events.recv().await.expect("stored event");
    assert_eq!(event.kind(), CacheEventKind::Stored);
    assert_eq!(event.key(), Some("user:42"));

    cache.invalidate_tag("users").await?;
    let invalidation = events.recv().await.expect("tag invalidation");
    assert_eq!(invalidation.kind(), CacheEventKind::TagInvalidated);

Mutation and invalidation events are published when subscribers exist. Hit, miss, and load events are higher volume, so they are opt-in with enable_access_events(true).

    let cache = HydraCache::local()
        .enable_access_events(true)
        .event_buffer_capacity(256)
        .build();
    let mut events = cache.subscribe_access();

    let answer = cache
        .get_or_insert_with("answer", CacheOptions::new(), || async { 42_u64 })
        .await?;

    assert_eq!(answer, 42);
    let event = events.next_event().await.expect("access event");
    assert_eq!(event.kind(), CacheEventKind::Miss);

Subscribers use a bounded buffer. Slow subscribers can lag, but cache operations do not wait for listeners.

Callback Listeners

Callback listeners are useful for lightweight integration points. Keep the returned handle alive for as long as the listener should be active.

    let cache = HydraCache::local().build();
    let listener = cache.on_mutation(|event| {
        println!("cache changed: {event:?}");
    });

    cache.put("user:42", 42_u64, CacheOptions::new()).await?;
    listener.unsubscribe();

HydraCache builds owned event payloads only when an event kind is enabled and at least one active subscriber can receive it.