neocrates 0.1.45

A comprehensive Rust library for various utilities and helpers
Documentation
# Redis Cache Module

The `rediscache` module is the Redis integration layer for Neocrates. It wraps `bb8-redis` with a friendly async API for pool creation, common Redis operations, pattern deletion, pipelines, distributed locks, and a simple global singleton.

See also: [root README](../../README.md)

---

## Feature

Enable with:

```toml
neocrates = { version = "0.1", default-features = false, features = ["redis"] }
```

---

## What this module exposes

### Configuration and pool

- `RedisConfig`
- `RedisPool::new(config)`
- `RedisPool::from_env()`
- `RedisPool::get_connection()`
- `RedisPool::get_pool_status()`

### Common operations

- `set`, `setex`, `get`, `del`, `exists`, `expire`, `ttl`
- `pipeline(...)`
- `del_by_pattern(pattern)`
- `del_prefix(prefix)`

### Lock helpers

- `acquire_lock(...)`
- `release_lock(...)`
- `lock_key(namespace, resource)`
- `try_acquire_lock_with_retry(...)`
- `release_lock_if(...)`

### Global pool helpers

- `init_redis_pool(config)`
- `get_redis_pool()`

### Key builders

- `RedisUtils::cache_key(...)`
- `RedisUtils::user_token_key(...)`
- `RedisUtils::user_session_key(...)`
- `RedisUtils::rate_limit_key(...)`
- `RedisUtils::thread_lock_key(...)`

---

## Quick start

```rust
use neocrates::rediscache::RedisPool;

async fn demo() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let pool = RedisPool::from_env().await?;
    pool.set("demo:key", "value").await?;
    let value: Option<String> = pool.get("demo:key").await?;
    println!("{value:?}");
    Ok(())
}
```

---

## Step-by-step tutorial

## 1. Start from environment variables

Supported variables:

- `REDIS_URL`
- `REDIS_MAX_SIZE`
- `REDIS_MIN_IDLE`
- `REDIS_CONNECTION_TIMEOUT`
- `REDIS_IDLE_TIMEOUT`
- `REDIS_MAX_LIFETIME`

Example:

```bash
export REDIS_URL="redis://127.0.0.1:6379"
export REDIS_MAX_SIZE=20
```

Then create the pool:

```rust
let pool = neocrates::rediscache::RedisPool::from_env().await?;
```

## 2. Read, write, and expire keys

```rust
pool.set("user:42", "neo").await?;
pool.setex("session:abc", "payload", 300).await?;

let user: Option<String> = pool.get("user:42").await?;
let ttl = pool.ttl("session:abc").await?;
println!("{user:?} {ttl}");
```

## 3. Delete a key range safely

```rust
let removed = pool.del_by_pattern("cache:*").await?;
println!("removed {removed} keys");

let removed2 = pool.del_prefix("tmp:").await?;
println!("removed {removed2} keys");
```

`del_by_pattern()` uses `SCAN` internally and attempts `UNLINK` before falling back to `DEL`.

## 4. Use a distributed lock

```rust
use std::time::Duration;

let key = neocrates::rediscache::RedisPool::lock_key("jobs", "daily-report");

if let Some(token) = pool.acquire_lock(&key, Duration::from_secs(10), None).await? {
    // critical section
    pool.release_lock(&key, &token).await?;
}
```

## 5. Initialize the global singleton if your app wants one shared pool

```rust
use neocrates::rediscache::{RedisConfig, init_redis_pool, get_redis_pool};

let config = RedisConfig::default();
init_redis_pool(config).await?;
let pool = get_redis_pool().unwrap();
```

---

## Key points and gotchas

- `RedisConfig::default()` panics if `REDIS_URL` is missing; `RedisPool::from_env()` is the safer option for most apps.
- The lock helpers use `SET NX PX` for acquisition and a Lua compare-and-delete script for release.
- `del_by_pattern()` is safer than `KEYS ...`-style deletion on large keyspaces, but it is still operational work you should use intentionally.
- The `redis` feature currently enables the `moka` dependency, but this module does not yet expose a high-level Moka wrapper.

---

## Roadmap

Useful next improvements:

1. Add typed JSON helpers for common cache value patterns.
2. Add a first-class Moka integration layer.
3. Add metrics/tracing around pool saturation and command timing.
4. Add namespace builders so callers do less manual key formatting.