Crate hitbox_actix[][src]

Expand description

Hitbox-Actix

Build status Coverage Status

Hitbox-Actix is an asynchronous caching framework for Actix actor framework. It’s designed for distributed and for single-machine applications.

Features

  • Automatic cache key generation.
  • Multiple cache backend implementations.
  • Stale cache mechanics.
  • Cache locks for dogpile effect preventions.
  • Distributed cache locks.
  • Detailed metrics out of the box.

Backend implementations:

  • Redis
  • In-memory backend

Feature flags

  • derive - Support for Cacheable trait derive macros.
  • redis - Support for default redis backend.

Restrictions

Default cache key implementation based on serde_qs crate and have some restrictions.

Documentation

Flow diagrams:

Simple flow

Example

Dependencies:

[dependencies]
hitbox_actix = "0.1"

Code:

First, you should derive Cacheable trait for your actix Message:

use actix::prelude::*;
use actix_derive::{Message, MessageResponse};
use hitbox_actix::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Message, Cacheable, Serialize)]
#[rtype(result = "Result<Pong, Error>")]
struct Ping {
    id: i32,
}

#[derive(MessageResponse, Deserialize, Serialize, Debug)]
struct Pong(i32);

#[derive(Debug)]
struct Error;

Next step is declare Upstream actor and implement actix Handler for Ping:

#[derive(Debug)]
struct UpstreamActor;

impl Actor for UpstreamActor {
    type Context = Context<Self>;
}

impl Handler<Ping> for UpstreamActor {
    type Result = ResponseFuture<<Ping as Message>::Result>;

    fn handle(&mut self, msg: Ping, _ctx: &mut Self::Context) -> Self::Result {
        println!("Handler::Ping");
        Box::pin(async move {
            actix_rt::time::sleep(core::time::Duration::from_secs(3)).await;
            Ok(Pong(msg.id))
        })
    }
}

The last step is initialize and start CacheActor and UpstreamActor:

use tracing_subscriber::EnvFilter;

#[actix_rt::main]
async fn main() -> Result<(), CacheError> {
    let filter = EnvFilter::new("hitbox=trace");
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::TRACE)
        .with_env_filter(filter)
        .init();

    let backend = RedisBackend::new()
        .await?
        .start();

    let cache = Cache::builder()
        .with_stale()
        .finish(backend)
        .start();
    let upstream = UpstreamActor.start();

    /// And send `Ping` message into cache actor
    let msg = Ping { id: 42 };
    let res = cache.send(msg.into_cache(&upstream)).await??;
    println!("{:#?}", res);
    Ok(())
}

Re-exports

pub use actor::CacheActor;
pub use builder::CacheBuilder;
pub use messages::IntoCache;
pub use messages::QueryCache;
pub use runtime::ActixAdapter;

Modules

actor

Cache actor and Builder.

builder

CacheActor builder patter implementation.

handlers

Actix Handler implementation.

messages

QueryCache message declaration and converting.

prelude

Prelude for hitbox_actix.

runtime

hitbox::runtime::RuntimeAdapter implementation for Actix runtime.

Structs

RedisBackend

Redis cache backend based on redis-rs crate.

Enums

CacheError

Base hitbox error.

Traits

Cacheable

Trait describes cache configuration per type that implements this trait.

Type Definitions

Cache

Default type alias with RedisBackend. You can disable it or define it manually in your code.

Derive Macros

Cacheable

Derive Cacheable macro implementation.