Prhub

#44382 [Rust Frontend] Add /abort_requests endpoint

原始 PR 作者 sahilsGit 合并时间 2026-06-17 14:40 文件变更 3 提交数 1 评论 6 代码增减 +145 / -0

执行摘要

为 Rust 前端添加 /abort_requests 端点

为 Rust 前端添加 /abort_requests 端点,作为 RL / admin / lifecycle APIs 路标的一部分(Issue #44280)。

值得精读,特别是了解 Rust 前端如何处理请求 ID 映射以及如何扩展管理 API。建议在合并前确保另一个 PR 的映射已到位。

讨论亮点

BugenZhao 指出 PR 混淆了外部和内部请求 ID:Python 前端通过 AsyncLLM 映射外部 ID 到内部 ID,而 Rust 的 Llm 随机生成内部 ID 但 abort 路由直接传递外部 ID,导致实际不会取消请求。作者创建另一个 PR 建立映射后,该 PR 获批准。

实现拆解

  1. 新增 abort_requests.rs 模块,定义 AbortRequestsRequest 结构体和 abort_requests 处理函数,解析 JSON 请求体并调用 state.chat.abort()
  2. routes.rs 中注册路由 /abort_requestsabort_requests::abort_requests 处理函数,并添加模块声明。
  3. tests.rs 中添加四个测试用例:正常请求、缺失 request_ids、畸形 JSON、空 ID 列表,覆盖成功和错误路径。
文件 模块 状态 重要度
rust/src/server/src/routes/abort_requests.rs Rust 服务 added 6.98
rust/src/server/src/routes.rs Rust 服务 modified 4.32
rust/src/server/src/routes/tests.rs Rust 服务 modified 7.86

关键符号

abort_requests AbortRequestsRequest abort_requests_route_returns_ok_for_well_formed_body abort_requests_route_rejects_missing_request_ids abort_requests_route_rejects_malformed_json abort_requests_route_accepts_empty_id_list

关键源码片段

rust/src/server/src/routes/abort_requests.rs entrypoint

核心新增文件,实现 /abort_requests 端点的主要逻辑

use std::sync::Arc;
use axum::Json;
use axum::extract::State;
use axum::extract::rejection::JsonRejection;
use axum::http::StatusCode;
use serde::Deserialize;use crate::error::ApiError;
use crate::state::AppState;
use crate::utils::utility_call_error;/// 请求体结构:request_ids 为可选字符串列表
#[derive(Debug, Deserialize)]
pub(crate) struct AbortRequestsRequest {
    request_ids: Option<Vec<String>>,
}/// POST /abort_requests 处理函数
pub async fn abort_requests(
    State(state): State<Arc<AppState>>,
    body: Result<Json<AbortRequestsRequest>, JsonRejection>,
) -> Result<StatusCode, ApiError> {
    // 尝试解析 JSON,若失败则返回 400
    let Json(body) = body.map_err(|error| ApiError::json_parse_error(error.body_text()))?;
    // 提取 request_ids,若缺失则返回 400 并指出参数名
    let request_ids = body.request_ids.ok_or_else(|| {
        ApiError::invalid_request(
            "Missing 'request_ids' in request body".to_string(),
            Some("request_ids"),
        )
    })?;
    // 调用底层 abort 方法,映射错误
    state
        .chat
        .abort(&request_ids)
        .await
        .map_err(|error| utility_call_error("abort_requests", error))?;
    // 成功返回 200 OK 无 body
    Ok(StatusCode::OK)
}
rust/src/server/src/routes.rs entrypoint

注册 /abort_requests 路由,使其在 dev_mode 下可用

// 在 routes.rs 中添加以下内容:mod abort_requests; // 新增模块声明// 在 build_router_with_options 函数的 dev_mode 代码块中注册路由:
if dev_mode_enabled {
    router = router
        .route("/reset_prefix_cache", post(cache::reset_prefix_cache))
        .route("/reset_mm_cache", post(cache::reset_mm_cache))
        .route("/reset_encoder_cache", post(cache::reset_encoder_cache))
        .route("/collective_rpc", post(collective_rpc::collective_rpc))
        .route("/abort_requests", post(abort_requests::abort_requests)) // 新增路由
        .route("/sleep", post(sleep::sleep))
        .route("/wake_up", post(sleep::wake_up))
        .route("/is_sleeping", get(sleep::is_sleeping))
        .route("/pause", post(pause::pause))
        .route("/resume", post(pause::resume))
        .route("/is_paused", get(pause::is_paused))
        .route("/server_info", get(server_info::server_info));
}
rust/src/server/src/routes/tests.rs test

添加四个测试用例,验证端点的正确性和错误处理

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[serial]
/// 测试正常请求:发送有效 request_ids 应返回 200 OK 且 body 为空
async fn abort_requests_route_returns_ok_for_well_formed_body() {
    let (app, engine_task) =
        test_admin_app_with_engine_script(|_dealer, _push| boxed_test_future(async move {})).await;    let response = app
        .clone()
        .call(
            Request::builder()
                .method("POST")
                .uri("/abort_requests")
                .header("content-type", "application/json")
                .body(Body::from(r#"{"request_ids":["req-1","req-2"]}"#))
                .expect("build request"),
        )
        .await
        .expect("call app");    let status = response.status();
    let body = to_bytes(response.into_body(), usize::MAX).await.expect("read body");
    assert_eq!(status, StatusCode::OK, "{}", String::from_utf8_lossy(&body));
    assert!(body.is_empty());
    engine_task.abort_and_join().await;
}

评论区精华

External/Internal request ID mapping 设计

BugenZhao 指出 PR 混淆了外部和内部请求 ID:Python 前端通过 AsyncLLM 映射外部 ID 到内部 ID,而 Rust 的 Llm 随机生成内部 ID 但 abort 路由直接传递外部 ID,导致实际不会取消请求。

结论:作者创建另一个 PR 建立外部到内部的映射,该 PR 获批准。 · 已解决

风险与影响

主要风险在于 ID 映射问题:如果映射未正确实现,abort_requests 可能返回 200 但实际无效。该问题已在另一 PR 中修复,风险可控。此外,该端点仅在开发模式下可用,不会影响生产流量。

对用户:Rust 前端用户现在可以通过 API 取消请求,便于管理长时间运行的任务。对系统:新增轻量级路由,无性能影响。对团队:作为 Rust 前端管理 API 的一部分,推进了 roadmap。

外部 / 内部 ID 映射依赖 开发模式限制

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论