use db::cache::AppCache; use db::database::AppDatabase; use models::rooms::room_message::{Column as RmCol, Entity as RoomMessage}; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QuerySelect}; use uuid::Uuid; use crate::error::RoomError; pub async fn next_room_message_seq_internal( room_id: Uuid, db: &AppDatabase, cache: &AppCache, ) -> Result { let seq_key = format!("room:seq:{}", room_id); let mut conn = cache.conn().await.map_err(|e| { RoomError::Internal(format!("failed to get redis connection for seq: {}", e)) })?; let seq: i64 = redis::cmd("INCR") .arg(&seq_key) .query_async(&mut conn) .await .map_err(|e| RoomError::Internal(format!("seq INCR: {}", e)))?; // DB reconciliation: only check every 1000 messages if seq % 1000 == 0 { let db_seq: Option>> = RoomMessage::find() .filter(RmCol::Room.eq(room_id)) .select_only() .column_as(RmCol::Seq.max(), "max_seq") .into_tuple::>>() .one(db) .await? .map(|r| r); let db_seq = db_seq.flatten().flatten().unwrap_or(0); if db_seq >= seq { let _: String = redis::cmd("SET") .arg(&seq_key) .arg(db_seq + 1) .query_async(&mut conn) .await .map_err(|e| RoomError::Internal(format!("seq SET: {}", e)))?; return Ok(db_seq + 1); } } Ok(seq) }