Mastering Redis Integration in Rust: Singleton & Connection Pool Guide

This article explains how to integrate Redis into a Rust backend by defining resource structs, wrapping the client with enums, implementing a connection pool using r2d2, creating a global singleton with once_cell, and providing example code for querying and storing data.

JD Cloud Developers
JD Cloud Developers
JD Cloud Developers
Mastering Redis Integration in Rust: Singleton & Connection Pool Guide

When developing backend applications, interacting with databases and caches like Redis is common. This guide shows how to query Redis and implement both singleton and connection‑pool patterns in Rust.

Key Crates

The implementation relies on three crates: once_cell – provides a thread‑safe singleton. redis‑rs – the official Redis driver for Rust. r2d2 – a generic connection‑pool library.

Redis Resource Definition

The RedisInstance struct mirrors the configuration file and describes a Redis resource.

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Clone)]
#[serde(rename_all = "lowercase")]
pub struct RedisInstance {
    #[serde(default = "RedisInstance::urls_default")]
    pub urls: Vec<String>,
    #[serde(default = "RedisInstance::password_default")]
    pub password: String,
    #[serde(default = "RedisInstance::instance_type_default")]
    pub instance_type: InstanceType,
}

Client and Connection Wrappers

The RedisClient enum abstracts single‑node and cluster connections, while RedisConnection represents the concrete connection types.

#[derive(Clone)]
pub enum RedisClient {
    Single(redis::Client),
    Cluster(redis::cluster::ClusterClient),
}

impl RedisClient {
    pub fn get_redis_connection(&self) -> RedisResult<RedisConnection> {
        match self {
            RedisClient::Single(s) => {
                let conn = s.get_connection()?;
                Ok(RedisConnection::Single(Box::new(conn)))
            }
            RedisClient::Cluster(c) => {
                let conn = c.get_connection()?;
                Ok(RedisConnection::Cluster(Box::new(conn)))
            }
        }
    }
}

pub enum RedisConnection {
    Single(Box<redis::Connection>),
    Cluster(Box<redis::cluster::ClusterConnection>),
}

impl RedisConnection {
    pub fn is_open(&self) -> bool {
        match self {
            RedisConnection::Single(sc) => sc.is_open(),
            RedisConnection::Cluster(cc) => cc.is_open(),
        }
    }
    pub fn query<T: FromRedisValue>(&mut self, cmd: &redis::Cmd) -> RedisResult<T> {
        match self {
            RedisConnection::Single(sc) => sc.as_mut().req_command(cmd).and_then(|v| from_redis_value(&v)),
            RedisConnection::Cluster(cc) => cc.req_command(cmd).and_then(|v| from_redis_value(&v)),
        }
    }
}

Connection Pool with r2d2

To enable pooling, a manager implementing r2d2::ManageConnection is defined.

#[derive(Clone)]
pub struct RedisConnectionManager {
    pub redis_client: RedisClient,
}

impl r2d2::ManageConnection for RedisConnectionManager {
    type Connection = RedisConnection;
    type Error = RedisError;

    fn connect(&self) -> Result<RedisConnection, Self::Error> {
        let conn = self.redis_client.get_redis_connection()?;
        Ok(conn)
    }

    fn is_valid(&self, conn: &mut RedisConnection) -> Result<(), Self::Error> {
        match conn {
            RedisConnection::Single(sc) => redis::cmd("PING").query(sc)?,
            RedisConnection::Cluster(cc) => redis::cmd("PING").query(cc)?,
        }
        Ok(())
    }

    fn has_broken(&self, conn: &mut RedisConnection) -> bool {
        !conn.is_open()
    }
}

Generating the Pool

The gen_redis_conn_pool function builds a pool based on configuration values such as maximum size, minimum idle connections, and timeout.

pub fn gen_redis_conn_pool() -> Result<Pool<RedisConnectionManager>> {
    let config = get_config()?;
    let redis_client = config.redis.instance.to_redis_client()?;
    let manager = RedisConnectionManager { redis_client };
    let pool = r2d2::Pool::builder()
        .max_size(config.redis.pool.max_size as u32)
        .min_idle(Some(config.redis.pool.mini_idle as u32))
        .connection_timeout(Duration::from_secs(config.redis.pool.connection_timeout as u64))
        .build(manager)?;
    Ok(pool)
}

Global Singleton

A static GLOBAL_REDIS_POOL is created with OnceCell to hold the pool.

pub static GLOBAL_REDIS_POOL: OnceCell<r2d2::Pool<RedisConnectionManager>> = OnceCell::new();

The initializer populates the cell, panicking if pool creation fails.

fn init_global_redis() {
    GLOBAL_REDIS_POOL.get_or_init(|| {
        match gen_redis_conn_pool() {
            Ok(it) => it,
            Err(err) => panic!("{}", err.to_string()),
        }
    });
}

Using the Pool

Example code shows how to obtain a connection from the global pool and execute a SET command.

pub fn put(kv: KV) -> Result<()> {
    let conn = GLOBAL_REDIS_POOL.get();
    match conn {
        Some(c) => {
            c.get()?.query(redis::cmd("set").arg(kv.Key).arg(kv.Value))?;
            Ok(())
        }
        None => Err(anyhow!("redis pool not init")),
    }
}

The full repository ( fullstack-rs ) contains the complete HTTP server flow that writes to Redis, though the HTTP layer is not covered here.

With these components, you can efficiently manage Redis connections in a Rust backend, leveraging both singleton access and a configurable connection pool.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backend DevelopmentRustredisConnection Poolr2d2once_cell
JD Cloud Developers
Written by

JD Cloud Developers

JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.