Skip to content

Caché ​

Guardar en memoria el resultado de una operación costosa evita repetirla en cada petición. CacheModule ofrece un almacén en memoria con caducidad (CacheManager) y un interceptor que cachea respuestas GET completas (CacheInterceptor).

Registrar el módulo ​

rust
#[module(
    imports = [CacheModule::register(CacheOptions { is_global: true, ..Default::default() })],
)]
pub struct AppModule;

(Así lo registra examples/cats-app.) CacheOptions:

CampoPor defectoSignificado
ttl5_000Tiempo de vida por defecto, en milisegundos (0 = no caduca)
max100Número máximo de entradas
is_globalfalseRegistra el módulo como global

Sin is_global: true, importa CacheModule::register(...) en cada módulo que lo use. Ten en cuenta que cada llamada a register crea un almacén distinto.

Cachear respuestas ​

Aplica CacheInterceptor a una ruta (o a todo el controlador) con #[use_interceptors]:

rust
#[get("count")]
#[use_interceptors(CacheInterceptor)]
#[set_metadata(CACHE_TTL_METADATA, 5_000)]
fn count(&self) -> Value {
    json!({ "count": self.cats_service.count() })
}

(De examples/cats-app/src/cats/cats_controller.rs.) Comportamiento:

  • Solo actúa en peticiones GET; los demás métodos pasan sin tocar la caché.
  • La clave es la URL de la petición (con su query string). #[set_metadata(CACHE_KEY_METADATA, "clave")] la reemplaza por una fija.
  • #[set_metadata(CACHE_TTL_METADATA, ms)] cambia el tiempo de vida para esa ruta o controlador.
  • Solo se guardan respuestas exitosas con cuerpo JSON, texto o HTML. Los archivos y los streams no se cachean.
  • Un acierto responde 200 con el cuerpo guardado; las cabeceras de la respuesta original no se guardan.

CacheInterceptor es un provider que necesita CacheManager: el módulo donde se usa debe poder verlo (importando CacheModule o registrándolo como global). Para aplicarlo a toda la aplicación, regístralo como interceptor global con inyección de dependencias:

rust
#[module(
    imports = [CacheModule::register(CacheOptions { is_global: true, ..Default::default() })],
    providers = [Provider::app_interceptor::<CacheInterceptor>()],
)]
pub struct AppModule;

Usar el almacén directamente ​

Inyecta Arc<CacheManager> (o, por token, #[inject(corvis::CACHE_MANAGER)] cache: Arc<CacheManager>):

rust
#[injectable]
pub struct RatesService {
    cache: Arc<CacheManager>,
}

impl RatesService {
    pub async fn usd_rate(&self) -> f64 {
        self.cache
            .wrap("rates:usd", Some(60_000), || async { fetch_rate().await })
            .await
    }

    pub async fn invalidate(&self) {
        self.cache.del("rates:usd").await;
    }
}
MétodoDescripción
get::<T>(clave).awaitOption<T>; None si no existe, caducó o no se puede convertir a T
set(clave, valor, ttl).awaitGuarda cualquier valor Serialize; ttl en ms (None = el de las opciones)
del(clave).awaitBorra una entrada
clear().awaitVacía el almacén
wrap(clave, ttl, closure).awaitDevuelve lo guardado o ejecuta la closure, guarda y devuelve su resultado
get_value(clave) / set_value(clave, valor, ttl)Versiones síncronas con serde_json::Value

Los valores se guardan como JSON. Cuando se supera max, se descarta la entrada más antigua por orden de inserción (no la menos usada).

Límites ​

  • El almacén vive en la memoria del proceso: no se comparte entre instancias ni sobrevive a un reinicio. No hay adaptadores para almacenes externos como Redis; si los necesitas, crea un provider propio con el cliente del almacén (ver Visión general).
  • La caché de respuestas no distingue usuarios: no la apliques a rutas cuyo contenido depende de quién hace la petición, salvo que fijes una clave que lo incluya.

Publicado bajo la licencia MIT.