gbserver/gb-messaging/src/redis_pubsub.rs

115 lines
2.7 KiB
Rust
Raw Normal View History

2024-12-22 20:56:52 -03:00
use async_trait::async_trait;
2024-12-23 00:20:59 -03:00
2024-12-22 20:56:52 -03:00
use gb_core::{Result, Error};
2024-12-23 00:20:59 -03:00
use redis::{Client, AsyncCommands};
2024-12-22 20:56:52 -03:00
use serde::{de::DeserializeOwned, Serialize};
use std::sync::Arc;
2024-12-23 00:20:59 -03:00
use tracing::instrument;
2024-12-22 20:56:52 -03:00
pub struct RedisPubSub {
2024-12-23 00:20:59 -03:00
client: Arc<Client>,
}
impl Clone for RedisPubSub {
fn clone(&self) -> Self {
Self {
client: self.client.clone(),
}
}
2024-12-22 20:56:52 -03:00
}
impl RedisPubSub {
pub async fn new(url: &str) -> Result<Self> {
let client = Client::open(url)
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::redis(e.to_string()))?;
2024-12-22 20:56:52 -03:00
2024-12-23 00:20:59 -03:00
// Test connection
client.get_async_connection()
2024-12-22 20:56:52 -03:00
.await
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::redis(e.to_string()))?;
2024-12-22 20:56:52 -03:00
Ok(Self {
2024-12-23 00:20:59 -03:00
client: Arc::new(client),
2024-12-22 20:56:52 -03:00
})
}
2024-12-23 00:20:59 -03:00
#[instrument(skip(self, payload))]
pub async fn publish<T>(&self, channel: &str, payload: &T) -> Result<()>
2024-12-22 20:56:52 -03:00
where
2024-12-23 00:20:59 -03:00
T: Serialize + std::fmt::Debug,
2024-12-22 20:56:52 -03:00
{
2024-12-23 00:20:59 -03:00
let mut conn = self.client.get_async_connection()
2024-12-22 20:56:52 -03:00
.await
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::redis(e.to_string()))?;
2024-12-22 20:56:52 -03:00
2024-12-23 00:20:59 -03:00
let payload = serde_json::to_string(payload)
.map_err(|e| Error::redis(e.to_string()))?;
2024-12-22 20:56:52 -03:00
2024-12-23 00:20:59 -03:00
conn.publish(channel, payload)
.await
.map_err(|e| Error::redis(e.to_string()))?;
2024-12-22 20:56:52 -03:00
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
2024-12-23 00:20:59 -03:00
use std::time::Duration;
2024-12-22 20:56:52 -03:00
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct TestMessage {
id: Uuid,
content: String,
}
#[fixture]
async fn redis_pubsub() -> RedisPubSub {
RedisPubSub::new("redis://localhost")
.await
.unwrap()
}
#[fixture]
fn test_message() -> TestMessage {
TestMessage {
id: Uuid::new_v4(),
content: "test message".to_string(),
}
}
#[rstest]
#[tokio::test]
async fn test_publish_subscribe(
redis_pubsub: RedisPubSub,
test_message: TestMessage,
) {
let channel = "test-channel";
let pubsub_clone = redis_pubsub.clone();
let test_message_clone = test_message.clone();
let handle = tokio::spawn(async move {
let handler = |msg: TestMessage| async move {
assert_eq!(msg, test_message_clone);
Ok(())
};
pubsub_clone.subscribe(&[channel], handler).await.unwrap();
});
tokio::time::sleep(Duration::from_millis(100)).await;
redis_pubsub.publish(channel, &test_message)
.await
.unwrap();
tokio::time::sleep(Duration::from_secs(1)).await;
handle.abort();
}
}