feat: 重试与超时策略细化(可配 + 退避)tsk_N5wO3Armums2
## 变更摘要 ### 1. 项目级可配重试上限与超时 - `Project` 新增 `maxRetries`(默认 2)和 `timeoutMs`(默认 30min = 1800000ms)字段 - SQLite schema:`projects` 表补 `max_retries` / `timeout_ms` 列(带 DEFAULT 的轻量迁移) - `createProject` / `patchProject` 支持设置 / 校验新字段(maxRetries>=0, timeoutMs>=1000) - API `POST /api/projects` 与 `PATCH /api/projects/:id` 透传新字段 - `runner.ts` 将 `project.timeoutMs` 传给 `runClaude`,不再固定 30min ### 2. 失败重试指数退避 - 编排器内存维护 `backoffUntil` Map(taskId → nextRetryAt),daemon 重启后清空 - 退避公式:`min(30s * 2^(attempt-1), 10min)`,第 1 次 30s / 第 2 次 60s / ... - `claimable()` 过滤退避冷却中的任务 - `nowMs` 注入点(默认 `Date.now`)使测试可快进时钟验证退避行为 ### 3. needs_attention 一键重投 - `Task` 新增 `retryBaseline` 字段(默认 0):记录上次重投时的失败 run 基线 - `Store.requeueTask(taskId)`:设置基线 = 当前失败 run 数 → 转 `queued`(仅限 needs_attention) - 编排器用净失败数(`allFailed - retryBaseline`)判断是否已耗尽重试次数 - API `POST /api/tasks/:id/requeue` + MCP `requeue_task` 工具 ### 4. 测试 - 重命名 `MAX_RETRIES` → `DEFAULT_MAX_RETRIES`,新增导出 `computeBackoffMs` - 新增测试(共 +18):maxRetries=1/0、退避时序(精确 ms 边界)、重投后基线重置 - 迁移测试扩展:验证旧库补列后 maxRetries/timeoutMs/retryBaseline 使用默认值 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,8 @@ export interface RunnerResult {
|
||||
export type RunnerFn = (task: Task, project: Project, worktree: WorktreeInfo, runId: string) => Promise<RunnerResult>;
|
||||
|
||||
const DEFAULT_MAX_TURNS = 100;
|
||||
const DEFAULT_TIMEOUT_MS = 30 * 60_000; // 整体兜底超时 30min
|
||||
/** 若项目未配置 timeoutMs 时的全局兜底超时(30min) */
|
||||
const DEFAULT_TIMEOUT_MS = 30 * 60_000;
|
||||
|
||||
/** 组装任务提示词:标题 + operations/spec 全文 + 执行约束 */
|
||||
export function buildPrompt(task: Task): string {
|
||||
@@ -58,13 +59,14 @@ async function ensureCommitted(dir: string, task: Task): Promise<void> {
|
||||
*/
|
||||
export async function runTask(task: Task, project: Project, worktree: WorktreeInfo, runId: string): Promise<RunnerResult> {
|
||||
const model = pickModel(task, project, 'executor');
|
||||
const timeoutMs = project.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
||||
const cc = await runClaude({
|
||||
prompt: buildPrompt(task),
|
||||
cwd: worktree.dir,
|
||||
model,
|
||||
runId,
|
||||
maxTurns: DEFAULT_MAX_TURNS,
|
||||
timeoutMs: DEFAULT_TIMEOUT_MS,
|
||||
timeoutMs,
|
||||
permissionMode: 'acceptEdits', // worktree 内自动接受编辑
|
||||
allowedTools: [
|
||||
'Read', 'Edit', 'Write', 'Glob', 'Grep',
|
||||
|
||||
Reference in New Issue
Block a user