feat: 引入 aether-runtime/cache/data/http/testkit 基础 crate,完善并发门控与审计系统

新增 crate:
- aether-runtime: 服务运行时基础设施(并发门控、分布式并发、指标、队列、优雅关闭、tracing)
- aether-cache: 通用 TTL 缓存与命名空间抽象
- aether-data: 数据访问层(PostgreSQL/Redis 后端、repository 模式)
- aether-http: HTTP 客户端封装(重试、配置)
- aether-testkit: 集成测试工具集(gateway/executor/hub/proxy fixture、等待、负载测试)

gateway 扩展:
- 引入 audit 模块(shadow 执行审计、决策链路追踪、请求审计 bundle)
- 引入 cache 模块(AuthContext 缓存、direct-plan bypass 缓存)
- 引入 data 模块(auth/candidates/config/usage/video_tasks 数据访问)
- 集成 ConcurrencyGate/DistributedConcurrencyGate 请求门控
- 新增本地 auth 拒绝、过载响应构建器
- 补充 control/auth_cache/video/concurrency 集成测试

aether-proxy 扩展:
- AppState 集成 stream_gate / distributed_stream_gate 并发门控
- 新增 ProxyAdmissionError 及准入拒绝流程
- stream_handler 补充门控饱和/不可用场景测试
- 配置与注册客户端逻辑完善

aether-hub 扩展:
- main.rs 引入运行时初始化、指标端点、健康检查
- local_relay 重构为 lib.rs 暴露公共接口
This commit is contained in:
fawney19
2026-03-24 15:12:56 +08:00
parent eaf8475f9e
commit b5a0070023
157 changed files with 22097 additions and 448 deletions
+202
View File
@@ -0,0 +1,202 @@
use futures_util::future::BoxFuture;
use sqlx::{Postgres, Transaction};
use crate::postgres::PostgresPool;
use crate::DataLayerError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TransactionMode {
ReadOnly,
#[default]
ReadWrite,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct PostgresTransactionOptions {
pub mode: TransactionMode,
pub statement_timeout_ms: Option<u64>,
pub lock_timeout_ms: Option<u64>,
}
impl PostgresTransactionOptions {
pub fn read_only() -> Self {
Self {
mode: TransactionMode::ReadOnly,
..Self::default()
}
}
pub fn read_write() -> Self {
Self {
mode: TransactionMode::ReadWrite,
..Self::default()
}
}
pub fn validate(&self) -> Result<(), DataLayerError> {
if matches!(self.statement_timeout_ms, Some(0)) {
return Err(DataLayerError::InvalidConfiguration(
"postgres statement_timeout_ms must be positive".to_string(),
));
}
if matches!(self.lock_timeout_ms, Some(0)) {
return Err(DataLayerError::InvalidConfiguration(
"postgres lock_timeout_ms must be positive".to_string(),
));
}
Ok(())
}
}
pub type PostgresTransaction = Transaction<'static, Postgres>;
#[derive(Debug, Clone)]
pub struct PostgresTransactionRunner {
pool: PostgresPool,
}
impl PostgresTransactionRunner {
pub fn new(pool: PostgresPool) -> Self {
Self { pool }
}
pub fn pool(&self) -> &PostgresPool {
&self.pool
}
pub async fn begin(
&self,
options: PostgresTransactionOptions,
) -> Result<PostgresTransaction, DataLayerError> {
options.validate()?;
let mut tx = self.pool.begin().await?;
for statement in build_transaction_setup_statements(options) {
sqlx::query(statement.as_str()).execute(&mut *tx).await?;
}
Ok(tx)
}
pub async fn run<T, F>(
&self,
options: PostgresTransactionOptions,
f: F,
) -> Result<T, DataLayerError>
where
F: for<'tx> FnOnce(
&'tx mut PostgresTransaction,
) -> BoxFuture<'tx, Result<T, DataLayerError>>,
{
let mut tx = self.begin(options).await?;
match f(&mut tx).await {
Ok(value) => {
tx.commit().await?;
Ok(value)
}
Err(err) => {
let _ = tx.rollback().await;
Err(err)
}
}
}
pub async fn run_read_only<T, F>(&self, f: F) -> Result<T, DataLayerError>
where
F: for<'tx> FnOnce(
&'tx mut PostgresTransaction,
) -> BoxFuture<'tx, Result<T, DataLayerError>>,
{
self.run(PostgresTransactionOptions::read_only(), f).await
}
pub async fn run_read_write<T, F>(&self, f: F) -> Result<T, DataLayerError>
where
F: for<'tx> FnOnce(
&'tx mut PostgresTransaction,
) -> BoxFuture<'tx, Result<T, DataLayerError>>,
{
self.run(PostgresTransactionOptions::read_write(), f).await
}
}
pub(crate) fn build_transaction_setup_statements(
options: PostgresTransactionOptions,
) -> Vec<String> {
let mut statements = Vec::new();
if options.mode == TransactionMode::ReadOnly {
statements.push("SET TRANSACTION READ ONLY".to_string());
}
if let Some(statement_timeout_ms) = options.statement_timeout_ms {
statements.push(format!(
"SET LOCAL statement_timeout = {}",
statement_timeout_ms
));
}
if let Some(lock_timeout_ms) = options.lock_timeout_ms {
statements.push(format!("SET LOCAL lock_timeout = {}", lock_timeout_ms));
}
statements
}
#[cfg(test)]
mod tests {
use super::{
build_transaction_setup_statements, PostgresTransactionOptions, PostgresTransactionRunner,
TransactionMode,
};
use crate::postgres::{PostgresPoolConfig, PostgresPoolFactory};
#[test]
fn validates_transaction_options() {
assert!(PostgresTransactionOptions {
statement_timeout_ms: Some(0),
..PostgresTransactionOptions::default()
}
.validate()
.is_err());
assert!(PostgresTransactionOptions {
lock_timeout_ms: Some(0),
..PostgresTransactionOptions::default()
}
.validate()
.is_err());
}
#[test]
fn builds_expected_setup_statements() {
let statements = build_transaction_setup_statements(PostgresTransactionOptions {
mode: TransactionMode::ReadOnly,
statement_timeout_ms: Some(1_500),
lock_timeout_ms: Some(750),
});
assert_eq!(
statements,
vec![
"SET TRANSACTION READ ONLY".to_string(),
"SET LOCAL statement_timeout = 1500".to_string(),
"SET LOCAL lock_timeout = 750".to_string(),
]
);
}
#[tokio::test]
async fn runner_reuses_lazy_pool() {
let factory = PostgresPoolFactory::new(PostgresPoolConfig {
database_url: "postgres://localhost/aether".to_string(),
min_connections: 1,
max_connections: 4,
acquire_timeout_ms: 1_000,
idle_timeout_ms: 5_000,
max_lifetime_ms: 30_000,
statement_cache_capacity: 64,
require_ssl: false,
})
.expect("factory should build");
let pool = factory.connect_lazy().expect("lazy pool should build");
let runner = PostgresTransactionRunner::new(pool.clone());
let _pool_ref = runner.pool();
}
}