use crate::database_err;
use crate::driver::non_blocking::get_tokio_context;
use crate::errors::AkitaError;
use async_trait::async_trait;
use deadpool::managed::{Metrics, Object, Pool, RecycleResult};
use deadpool::Runtime;
use mysql_async::prelude::Queryable;
use mysql_async::{Conn, Opts};
use tokio::runtime::Handle;
pub type MysqlAsyncPool = Pool<MysqlAsyncConnectionManager>;
pub type MysqlAsyncConnection = Object<MysqlAsyncConnectionManager>;
#[derive(Clone)]
pub struct MysqlAsyncConnectionManager {
opts: Opts,
config: crate::config::AkitaConfig,
}
impl MysqlAsyncConnectionManager {
pub fn new(config: &crate::config::AkitaConfig) -> Result<Self, AkitaError> {
let connection_string = config.get_connection_string()?;
let opts = Opts::from_url(&connection_string)
.map_err(|e| database_err!(format!("Invalid MySQL URL: {}", e)))?;
Ok(Self {
opts,
config: config.clone(),
})
}
}
#[async_trait]
impl deadpool::managed::Manager for MysqlAsyncConnectionManager {
type Type = Conn;
type Error = mysql_async::Error;
async fn create(&self) -> Result<Self::Type, Self::Error> {
let mut conn = Conn::new(self.opts.clone()).await?;
let _ = conn
.query_drop(format!(
"SET SESSION max_execution_time = {}",
self.config.get_connection_timeout().as_millis()
))
.await;
Ok(conn)
}
async fn recycle(
&self,
obj: &mut Self::Type,
_metrics: &Metrics,
) -> RecycleResult<Self::Error> {
obj.ping().await?;
Ok(())
}
}
pub async fn init_mysql_async_pool(
config: crate::config::AkitaConfig,
) -> Result<MysqlAsyncPool, AkitaError> {
let manager = MysqlAsyncConnectionManager::new(&config)?;
let _handle = get_tokio_context()?;
let pool_config = deadpool::managed::PoolConfig {
max_size: config.get_max_size() as usize,
timeouts: deadpool::managed::Timeouts {
wait: Some(config.get_connection_timeout()),
create: Some(config.get_connection_timeout()),
recycle: Some(config.get_idle_timeout()),
},
..Default::default()
};
let pool = Pool::builder(manager)
.runtime(Runtime::Tokio1)
.config(pool_config)
.build()?;
let mut conn: MysqlAsyncConnection = pool
.get()
.await
.map_err(|e| database_err!(format!("Failed to get connection from pool: {}", e)))?;
conn.query_drop("SELECT 1")
.await
.map_err(|e| database_err!(format!("MySQL async connection test failed: {}", e)))?;
tracing::info!("MySQL async connection pool initialized successfully");
Ok(pool)
}