hitbox_actix/
lib.rs

1#![warn(missing_docs)]
2//! # Hitbox-Actix
3//!
4//! [![Build status](https://github.com/hit-box/hitbox/actions/workflows/CI.yml/badge.svg)](https://github.com/hit-box/hitbox/actions?query=workflow)
5//! [![Coverage Status](https://codecov.io/gh/hit-box/hitbox/branch/master/graph/badge.svg?token=tgAm8OBLkY)](https://codecov.io/gh/hit-box/hitbox)
6//!
7//! Hitbox-Actix is an asynchronous caching framework for [Actix] actor framework.
8//! It's designed for distributed and for single-machine applications.
9//!
10//! ## Features
11//! - [x] Automatic cache key generation.
12//! - [x] Multiple cache backend implementations.
13//! - [x] Stale cache mechanics.
14//! - [ ] Cache locks for [dogpile effect] preventions.
15//! - [ ] Distributed cache locks.
16//! - [ ] Detailed metrics out of the box.
17//!
18//! ## Backend implementations:
19//! - [x] [Redis](https://github.com/hit-box/hitbox/tree/master/hitbox-backend)
20//! - [ ] In-memory backend
21//!
22//! ## Feature flags
23//! * derive - Support for [Cacheable] trait derive macros.
24//! * redis - Support for default redis backend.
25//!
26//! ## Restrictions
27//! Default cache key implementation based on serde_qs crate
28//! and have some [restrictions](https://docs.rs/serde_qs/latest/serde_qs/#supported-types).
29//!
30//! ## Documentation
31//! * [API Documentation](https://docs.rs/hitbox_acitx/)
32//! * [Examples](https://github.com/hit-box/hitbox/tree/master/examples/examples)
33//!
34//! ### Flow diagrams:
35//! [![Simple flow](http://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/hit-box/hitbox/master/documentation/simple_flow.puml)](http://www.plantuml.com/plantuml/proxy?src=https://raw.githubusercontent.com/hit-box/hitbox/master/documentation/simple_flow.puml)
36//!
37//! ## Example
38//!
39//! ### Dependencies:
40//!
41//! ```toml
42//! [dependencies]
43//! hitbox_actix = "0.1"
44//! ```
45//!
46//! ### Code:
47//!
48//! First, you should derive [Cacheable] trait for your actix [Message]:
49//!
50//! ```rust,ignore
51//! use actix::prelude::*;
52//! use actix_derive::{Message, MessageResponse};
53//! use hitbox_actix::prelude::*;
54//! use serde::{Deserialize, Serialize};
55//!
56//! #[derive(Message, Cacheable, Serialize)]
57//! #[rtype(result = "Result<Pong, Error>")]
58//! struct Ping {
59//!     id: i32,
60//! }
61//!
62//! #[derive(MessageResponse, Deserialize, Serialize, Debug)]
63//! struct Pong(i32);
64//!
65//! #[derive(Debug)]
66//! struct Error;
67//! ```
68//!
69//! Next step is declare Upstream actor and implement actix Handler for Ping:
70//!
71//! ```rust,ignore
72//! #[derive(Debug)]
73//! struct UpstreamActor;
74//!
75//! impl Actor for UpstreamActor {
76//!     type Context = Context<Self>;
77//! }
78//!
79//! impl Handler<Ping> for UpstreamActor {
80//!     type Result = ResponseFuture<<Ping as Message>::Result>;
81//!
82//!     fn handle(&mut self, msg: Ping, _ctx: &mut Self::Context) -> Self::Result {
83//!         println!("Handler::Ping");
84//!         Box::pin(async move {
85//!             actix_rt::time::sleep(core::time::Duration::from_secs(3)).await;
86//!             Ok(Pong(msg.id))
87//!         })
88//!     }
89//! }
90//! ```
91//! The last step is initialize and start CacheActor and UpstreamActor:
92//!
93//! ```rust,ignore
94//! use tracing_subscriber::EnvFilter;
95//!
96//! #[actix_rt::main]
97//! async fn main() -> Result<(), CacheError> {
98//!     let filter = EnvFilter::new("hitbox=trace");
99//!     tracing_subscriber::fmt()
100//!         .with_max_level(tracing::Level::TRACE)
101//!         .with_env_filter(filter)
102//!         .init();
103//!
104//!     let backend = RedisBackend::new()
105//!         .await?
106//!         .start();
107//!
108//!     let cache = Cache::builder()
109//!         .with_stale()
110//!         .finish(backend)
111//!         .start();
112//!     let upstream = UpstreamActor.start();
113//!
114//!     /// And send `Ping` message into cache actor
115//!     let msg = Ping { id: 42 };
116//!     let res = cache.send(msg.into_cache(&upstream)).await??;
117//!     println!("{:#?}", res);
118//!     Ok(())
119//! }
120//! ```
121//!
122//! [Cacheable]: hitbox::Cacheable
123//! [CacheableResponse]: hitbox::CacheableResponse
124//! [Backend]: hitbox_backend::Backend
125//! [RedisBackend]: hitbox_redis::RedisActor
126//! [dogpile effect]: https://www.sobstel.org/blog/preventing-dogpile-effect/
127//! [Message]: actix::Message
128//! [Actix]: https://github.com/actix/actix/
129
130pub mod actor;
131pub mod builder;
132pub mod handlers;
133pub mod messages;
134pub mod runtime;
135
136pub use actor::CacheActor;
137pub use builder::CacheBuilder;
138pub use hitbox::{CacheError, Cacheable};
139pub use messages::{IntoCache, QueryCache};
140pub use runtime::ActixAdapter;
141
142#[cfg(feature = "redis")]
143pub use hitbox_redis::RedisBackend;
144
145/// Default type alias with RedisBackend.
146/// You can disable it or define it manually in your code.
147#[cfg(feature = "redis")]
148pub type Cache = CacheActor<RedisBackend>;
149
150/// Prelude for hitbox_actix.
151pub mod prelude {
152    #[cfg(feature = "redis")]
153    pub use crate::{Cache, RedisBackend};
154    pub use crate::{CacheActor, CacheBuilder, CacheError, Cacheable, IntoCache, QueryCache};
155    pub use hitbox::hitbox_serializer;
156}