添加qiming-rcoder模块

This commit is contained in:
Codex
2026-06-01 13:54:52 +08:00
parent 8092c4b1f8
commit 4b1a580132
539 changed files with 151650 additions and 0 deletions

View File

@@ -0,0 +1,355 @@
//! Agent Runtime 模块
//!
//! 简化版的 Agent Worker 管理器,利用 SACP 的 Send trait 支持。
//!
//! ## 新架构设计
//!
//! - 移除独立 OS 线程,使用 `tokio::spawn`
//! - 简化 sender 管理,移除 ArcSwap
//! - 保留自动重启功能
//! - 保留心跳检测(僵尸检测)
//! - 简化状态机(使用原子操作)
//!
//! ## 与旧架构对比
//!
//! | 组件 | 旧设计 | 新设计 |
//! |------|--------|--------|
//! | 运行环境 | 独立 OS 线程 + 独立运行时 | 主运行时 + tokio::spawn |
//! | Sender 管理 | ArcSwap<Option<Sender>> | mpsc::Sender (固定) |
//! | Worker 生命周期 | 手动管理线程 | JoinHandle |
//! | Ready 信号 | oneshot::channel | JoinHandle 完成 |
//! | 状态机 | watch::Sender + Mutex | Arc<AtomicState> |
//! | 重启 | 替换 sender | abort + spawn |
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::atomic::{AtomicI64, AtomicU8, AtomicUsize, Ordering};
use std::time::Duration;
use chrono::Utc;
use tokio::sync::{Mutex, mpsc};
use tokio::task::JoinHandle;
use tracing::{info, warn};
use crate::proxy_agent::AgentRequest;
/// Worker 状态
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WorkerState {
/// 启动中
Starting = 0,
/// 运行中
Running = 1,
/// 停止中
Stopping = 2,
/// 已停止
Stopped = 3,
}
/// 原子状态包装器 (无需 Mutex)
pub struct AtomicState(AtomicU8);
impl AtomicState {
pub fn new(state: WorkerState) -> Self {
Self(AtomicU8::new(state as u8))
}
pub fn get(&self) -> WorkerState {
match self.0.load(Ordering::Acquire) {
0 => WorkerState::Starting,
1 => WorkerState::Running,
2 => WorkerState::Stopping,
3 => WorkerState::Stopped,
invalid => {
tracing::error!(
"[AtomicState] Invalid state value: {}, falling back to Stopped",
invalid
);
WorkerState::Stopped
}
}
}
pub fn set(&self, state: WorkerState) {
self.0.store(state as u8, Ordering::Release);
}
}
/// 心跳包
#[derive(Clone, Debug)]
pub struct Heartbeat {
/// 心跳时间戳
pub timestamp: chrono::DateTime<chrono::Utc>,
}
/// Worker 就绪信号
///
/// Worker 在初始化完成后发送此信号
#[derive(Clone, Debug)]
pub struct WorkerReady {
/// 就绪时间戳
pub timestamp: chrono::DateTime<chrono::Utc>,
}
/// 并发控制配置
///
/// 工作线程池大小 - 决定可以并发处理的 Agent 会话数量
/// 🔥 已改为运行时可配置的全局变量,使用 get_concurrency_limit() 获取
/// 全局并发限制(运行时可配置)
pub static WORKER_THREAD_POOL_SIZE: AtomicUsize = AtomicUsize::new(10);
/// 初始化并发限制(在应用启动时调用)
pub fn init_concurrency_limit(limit: usize) {
WORKER_THREAD_POOL_SIZE.store(limit, Ordering::Release);
info!("🔧 Concurrency limit initialized: {}", limit);
}
/// 获取当前并发限制
pub fn get_concurrency_limit() -> usize {
WORKER_THREAD_POOL_SIZE.load(Ordering::Acquire)
}
/// Agent 运行时
///
/// 替代 AgentWorkerManager使用简化的架构
/// - 直接在主运行时中运行 (SACP 支持 Send)
/// - 使用原子操作管理状态
/// - 使用 JoinHandle 管理生命周期
pub struct AgentRuntime {
/// 请求发送端 (固定不变)
request_tx: mpsc::Sender<AgentRequest>,
/// 当前 Worker 的 JoinHandle
worker_handle: Arc<Mutex<Option<JoinHandle<()>>>>,
/// 当前状态
state: Arc<AtomicState>,
/// 🔥 P1 修复: 最后心跳时间戳毫秒Unix timestamp
/// 使用 AtomicI64 替代 Mutex避免频繁的锁竞争
/// - 0 表示从未收到心跳
/// - 正数表示最后一次心跳的 timestamp_millis()
last_heartbeat_ts: Arc<AtomicI64>,
/// 活跃请求追踪: request_id -> 开始时间
active_requests: Arc<Mutex<HashMap<String, chrono::DateTime<chrono::Utc>>>>,
/// 心跳超时阈值
heartbeat_timeout: Duration,
/// 首次启动宽限期
initial_grace_period: Duration,
}
impl AgentRuntime {
/// 创建新的 AgentRuntime
///
/// 返回 (runtime, request_receiver)
pub fn new(request_buffer: usize) -> (Self, mpsc::Receiver<AgentRequest>) {
let (request_tx, request_rx) = mpsc::channel(request_buffer);
let runtime = Self {
request_tx,
worker_handle: Arc::new(Mutex::new(None)),
state: Arc::new(AtomicState::new(WorkerState::Starting)),
last_heartbeat_ts: Arc::new(AtomicI64::new(0)),
active_requests: Arc::new(Mutex::new(HashMap::new())),
heartbeat_timeout: Duration::from_secs(15),
initial_grace_period: Duration::from_secs(30),
};
(runtime, request_rx)
}
/// 启动 Worker (在主运行时中)
///
/// SACP 支持 Send直接在主运行时中运行无需独立线程
pub async fn start(&self, receiver: mpsc::Receiver<AgentRequest>) {
let state = self.state.clone();
let last_heartbeat_ts = self.last_heartbeat_ts.clone();
let active_requests = self.active_requests.clone();
let handle = tokio::spawn(async move {
// SACP 支持 Send直接在主运行时中运行
if let Err(e) = crate::proxy_agent::agent_worker_with_heartbeat(
receiver,
state.clone(),
last_heartbeat_ts.clone(),
active_requests.clone(),
)
.await
{
tracing::error!("Agent worker failed: {}", e);
}
});
*self.worker_handle.lock().await = Some(handle);
self.state.set(WorkerState::Running);
info!("AgentRuntime: worker started");
}
/// 重启 Worker
pub async fn restart(&self, new_receiver: mpsc::Receiver<AgentRequest>) {
warn!("AgentRuntime: preparing to restart worker...");
// 1. 停止旧 worker
if let Some(handle) = self.worker_handle.lock().await.take() {
handle.abort();
info!("AgentRuntime: previous worker terminated");
}
// 2. 重置状态
self.state.set(WorkerState::Starting);
self.last_heartbeat_ts.store(0, Ordering::Release);
*self.active_requests.lock().await = HashMap::new();
// 3. 启动新 worker
self.start(new_receiver).await;
info!("AgentRuntime: worker restart completed");
}
/// 发送请求
pub async fn send(&self, request: AgentRequest) -> anyhow::Result<()> {
self.request_tx
.send(request)
.await
.map_err(|_| anyhow::anyhow!("Worker is closed"))?;
Ok(())
}
/// 健康检查
pub async fn check_health(&self) -> bool {
let state = self.state.get();
// 检查状态
if state == WorkerState::Stopped {
return false;
}
// 🔥 P1 修复: 使用原子操作检查心跳(无锁)
let last_ts = self.last_heartbeat_ts.load(Ordering::Acquire);
if last_ts > 0 {
let elapsed_ms = Utc::now().timestamp_millis() - last_ts;
elapsed_ms < self.heartbeat_timeout.as_millis() as i64
} else {
// 首次启动宽限期
true
}
}
/// 获取当前状态
pub fn state(&self) -> WorkerState {
self.state.get()
}
/// 🔥 P1 修复: 检查心跳是否超时(无锁)
///
/// ## 返回值
///
/// - `true`: 心跳超时(超过 15 秒未收到心跳)
/// - `false`: 心跳正常或在宽限期内
pub fn check_heartbeat_timeout(&self) -> bool {
let last_ts = self.last_heartbeat_ts.load(Ordering::Acquire);
if last_ts > 0 {
// 有心跳记录,检查是否超过 15 秒
let elapsed_ms = Utc::now().timestamp_millis() - last_ts;
elapsed_ms > 15_000
} else {
// 从未收到心跳,使用首次启动宽限期
false
}
}
/// 🔥 P1 修复: 获取最后心跳时间(无锁)
///
/// ## 返回值
///
/// - `Some(timestamp)`: 最后心跳时间
/// - `None`: 从未收到心跳
pub fn last_heartbeat_time(&self) -> Option<chrono::DateTime<chrono::Utc>> {
let last_ts = self.last_heartbeat_ts.load(Ordering::Acquire);
if last_ts > 0 {
// 将毫秒时间戳转换为 DateTime
use chrono::TimeZone;
// timestamp_millis_opt 返回 LocalResult使用 single() 转换为 Option
match chrono::Utc.timestamp_millis_opt(last_ts).single() {
Some(dt) => Some(dt),
None => {
tracing::warn!(
"[WorkerInfo] Invalid timestamp: {}, using current time",
last_ts
);
Some(chrono::Utc::now())
}
}
} else {
None
}
}
/// 获取活跃请求句柄
pub fn active_requests(&self) -> Arc<Mutex<HashMap<String, chrono::DateTime<chrono::Utc>>>> {
self.active_requests.clone()
}
/// 检查请求通道是否已关闭
pub fn is_closed(&self) -> bool {
self.request_tx.is_closed()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_atomic_state() {
let state = AtomicState::new(WorkerState::Starting);
assert_eq!(state.get(), WorkerState::Starting);
state.set(WorkerState::Running);
assert_eq!(state.get(), WorkerState::Running);
state.set(WorkerState::Stopped);
assert_eq!(state.get(), WorkerState::Stopped);
}
#[tokio::test]
async fn test_agent_runtime_creation() {
let (runtime, _rx) = AgentRuntime::new(100);
assert_eq!(runtime.state(), WorkerState::Starting);
assert!(!runtime.is_closed());
}
#[tokio::test]
async fn test_heartbeat_timeout_detection() {
let (runtime, _rx) = AgentRuntime::new(100);
// 初始状态:从未收到心跳
assert!(!runtime.check_heartbeat_timeout());
// 模拟心跳超时设置20秒前的时间戳
let timestamp_20s_ago = Utc::now().timestamp_millis() - (20 * 1000);
runtime
.last_heartbeat_ts
.store(timestamp_20s_ago, std::sync::atomic::Ordering::Release);
// 心跳超过 15 秒,应检测到超时
assert!(runtime.check_heartbeat_timeout());
}
#[tokio::test]
async fn test_health_check() {
let (runtime, _rx) = AgentRuntime::new(100);
// 初始状态应该是健康的
assert!(runtime.check_health().await);
// 设置状态为 Stopped
runtime.state.set(WorkerState::Stopped);
assert!(!runtime.check_health().await);
}
}