关于 session-timeout-handler
面向 Claude Code 的技能,用于围绕工具默认的 120 秒超时限制组织长任务。它提供分批处理、检查点、进度跟踪和可恢复模式,适合可能超出单次会话时限的工作流。
主要功能
- 01分批处理
- 02基于检查点恢复
- 03状态机工作流
- 04进度跟踪
- 05限速并行处理
- 06超时回退模式
适用场景
- 01分批处理大型数据集
- 02克隆多个代码仓库
- 03执行批量 API 请求
- 04将长任务拆分到多个 Claude Code 轮次
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jackspace/ claudeskillz --skill session-timeout-handler安装后在 Claude Code 中输入/session-timeout-handler确认已加载。
详细介绍
会话超时处理器
构建可靠的工作流,妥善处理 Claude Code 的 2 分钟超时限制。
概述
Claude Code 的默认工具超时时间为 120 秒(2 分钟)。此技能提供经过验证的模式,通过智能分块、检查点和断点续跑,在此限制内构建工作流,同时完成复杂、耗时较长的任务。
适用场景
在以下情况使用此技能:
- 在循环中处理 50 项或更多内容
- 运行耗时超过 60 秒的命令
- 下载多个大文件
- 批量调用 API
- 处理大型数据集
- 运行数据库迁移
- 构建大型项目
- 克隆多个代码仓库
- 任何有超时风险的操作
核心策略
策略 1:批处理
#!/bin/bash
# Process items in small batches
ITEMS_FILE="items.txt"
BATCH_SIZE=10
OFFSET=${1:-0}
# Process one batch
tail -n +$((OFFSET + 1)) "$ITEMS_FILE" | head -$BATCH_SIZE | while read item; do
process_item "$item"
echo "✓ Processed: $item"
done
# Calculate next offset
NEXT_OFFSET=$((OFFSET + BATCH_SIZE))
TOTAL=$(wc -l < "$ITEMS_FILE")
if [ $NEXT_OFFSET -lt $TOTAL ]; then
echo ""
echo "Progress: $NEXT_OFFSET/$TOTAL"
echo "Run: ./script.sh $NEXT_OFFSET"
else
echo "✓ All items processed!"
fi
策略 2:检查点续跑
#!/bin/bash
# Checkpoint-based workflow
CHECKPOINT_FILE=".progress"
ITEMS=("item1" "item2" "item3" ... "item100")
# Load last checkpoint
LAST_COMPLETED=$(cat "$CHECKPOINT_FILE" 2>/dev/null || echo "-1")
START_INDEX=$((LAST_COMPLETED + 1))
# Process next batch (10 items)
END_INDEX=$((START_INDEX + 10))
[ $END_INDEX -gt ${#ITEMS[@]} ] && END_INDEX=${#ITEMS[@]}
for i in $(seq $START_INDEX $END_INDEX); do
process "${ITEMS[$i]}"
# Save checkpoint after each item
echo "$i" > "$CHECKPOINT_FILE"
echo "✓ Completed $i/${#ITEMS[@]}"
done
# Check if finished
if [ $END_INDEX -eq ${#ITEMS[@]} ]; then
echo "🎉 All items complete!"
rm "$CHECKPOINT_FILE"
else
echo "📋 Run again to continue from item $((END_INDEX + 1))"
fi
策略 3:状态机
#!/bin/bash
# Multi-phase state machine workflow
STATE_FILE=".workflow_state"
STATE=$(cat "$STATE_FILE" 2>/dev/null || echo "INIT")
case $STATE in
INIT)
echo "Phase 1: Initialization"
setup_environment
echo "DOWNLOAD" > "$STATE_FILE"
echo "✓ Phase 1 complete. Run again for Phase 2."
;;
DOWNLOAD)
echo "Phase 2: Download (batch 1/5)"
download_batch_1
echo "PROCESS_1" > "$STATE_FILE"
echo "✓ Phase 2 complete. Run again for Phase 3."
;;
PROCESS_1)
echo "Phase 3: Process (batch 1/3)"
process_batch_1
echo "PROCESS_2" > "$STATE_FILE"
echo "✓ Phase 3 complete. Run again for Phase 4."
;;
PROCESS_2)
echo "Phase 4: Process (batch 2/3)"
process_batch_2
echo "PROCESS_3" > "$STATE_FILE"
echo "✓ Phase 4 complete. Run again for Phase 5."
;;
PROCESS_3)
echo "Phase 5: Process (batch 3/3)"
process_batch_3
echo "FINALIZE" > "$STATE_FILE"
echo "✓ Phase 5 complete. Run again to finalize."
;;
FINALIZE)
echo "Phase 6: Finalization"
cleanup_and_report
echo "COMPLETE" > "$STATE_FILE"
echo "🎉 Workflow complete!"
;;
COMPLETE)
echo "Workflow already completed."
cat results.txt
;;
esac
策略 4:进度跟踪
#!/bin/bash
# Detailed progress tracking with JSON
PROGRESS_FILE="progress.json"
# Initialize progress
init_progress() {
cat > "$PROGRESS_FILE" << EOF
{
"total": $1,
"completed": 0,
"failed": 0,
"last_updated": "$(date -Iseconds)",
"completed_items": []
}
EOF
}
# Update progress
update_progress() {
local item="$1"
local status="$2" # "success" or "failed"
# Read current progress
local completed=$(jq -r '.completed' "$PROGRESS_FILE")
local failed=$(jq -r '.failed' "$PROGRESS_FILE")
if [ "$status" = "success" ]; then
completed=$((completed + 1))
else
failed=$((failed + 1))
fi
# Update JSON
jq --arg item "$item" \
--arg status "$status" \
--arg timestamp "$(date -Iseconds)" \
--argjson completed "$completed" \
--argjson failed "$failed" \
'.completed = $completed |
.failed = $failed |
.last_updated = $timestamp |
.completed_items += [{item: $item, status: $status, timestamp: $timestamp}]' \
"$PROGRESS_FILE" > "$PROGRESS_FILE.tmp"
mv "$PROGRESS_FILE.tmp" "$PROGRESS_FILE"
}
# Show progress
show_progress() {
jq -r '"Progress: \(.completed)/\(.total) completed, \(.failed) failed"' "$PROGRESS_FILE"
}
# Example usage
init_progress 100
for item in $(seq 1 10); do # Process 10 at a time
if process_item "$item"; then
update_progress "item-$item" "success"
else
update_progress "item-$item" "failed"
fi
done
show_progress
安全应对超时的模式
模式:带速率限制的并行处理
#!/bin/bash
# Process items in parallel with limits
MAX_PARALLEL=3
ACTIVE_JOBS=0
process_with_limit() {
local item="$1"
# Wait if at max parallel
while [ $ACTIVE_JOBS -ge $MAX_PARALLEL ]; do
wait -n # Wait for any job to finish
ACTIVE_JOBS=$((ACTIVE_JOBS - 1))
done
# Start background job
(
process_item "$item"
echo "✓ $item"
) &
ACTIVE_JOBS=$((ACTIVE_JOBS + 1))
# Rate limiting
sleep 0.5
}
# Process items
for item in $(seq 1 15); do
process_with_limit "item-$item"
done
# Wait for remaining
wait
echo "✓ All processing complete"
模式:超时后回退
#!/bin/bash
# Try with timeout, fallback to cached/partial result
OPERATION_TIMEOUT=90 # 90 seconds, leave buffer
if timeout ${OPERATION_TIMEOUT}s expensive_operation > result.txt 2>&1; then
echo "✓ Operation completed"
cat result.txt
else
EXIT_CODE=$?
if [ $EXIT_CODE -eq 124 ]; then
echo "⚠️ Operation timed out after ${OPERATION_TIMEOUT}s"
# Use cached result if available
if [ -f "cached_result.txt" ]; then
echo "Using cached result from $(stat -c %y cached_result.txt)"
cat cached_result.txt
else
echo "Partial result:"
cat result.txt
echo ""
echo "Run again to continue processing"
fi
else
echo "✗ Operation failed with code $EXIT_CODE"
fi
fi
模式:增量构建
#!/bin/bash
# Incremental build with caching
BUILD_CACHE=".build_cache"
SOURCE_DIR="src"
# Track what needs rebuilding
mkdir -p "$BUILD_CACHE"
# Find changed files
find "$SOURCE_DIR" -type f -newer "$BUILD_CACHE/last_build" 2>/dev/null > changed_files.txt
if [ ! -s changed_files.txt ]; then
echo "✓ No changes detected, using cached build"
exit 0
fi
# Build only changed files (in batches)
head -10 changed_files.txt | while read file; do
echo "Building: $file"
build_file "$file"
done
# Update timestamp
touch "$BUILD_CACHE/last_build"
REMAINING=$(tail -n +11 changed_files.txt | wc -l)
if [ $REMAINING -gt 0 ]; then
echo ""
echo "⚠️ $REMAINING files remaining. Run again to continue."
else
echo "✓ Build complete!"
fi
实际示例
示例 1:批量克隆代码仓库
#!/bin/bash
# Clone 50 repos without timing out
REPOS_FILE="repos.txt"
CHECKPOINT="cloned.txt"
BATCH_SIZE=5
# Skip already cloned
while read repo_url; do
# Check checkpoint
if grep -qF "$repo_url" "$CHECKPOINT" 2>/dev/null; then
echo "✓ Skip: $repo_url (already cloned)"
continue
fi
REPO_NAME=$(basename "$repo_url" .git)
# Clone with timeout
if timeout 60s git clone --depth 1 "$repo_url" "$REPO_NAME" 2>/dev/null; then
echo "$repo_url" >> "$CHECKPOINT"
echo "✓ Cloned: $REPO_NAME"
else
echo "✗ Failed: $REPO_NAME"
fi
done < <(head -$BATCH_SIZE "$REPOS_FILE")
# Progress
CLONED=$(wc -l < "$CHECKPOINT" 2>/dev/null || echo 0)
TOTAL=$(wc -l < "$REPOS_FILE")
echo ""
echo "Progress: $CLONED/$TOTAL repositories"
[ $CLONED -lt $TOTAL ] && echo "Run again to continue"
示例 2:处理大型数据集
#!/bin/bash
# Process 1000 data files in batches
DATA_DIR="data"
OUTPUT_DIR="processed"
BATCH_NUM=${1:-1}
BATCH_SIZE=20
mkdir -p "$OUTPUT_DIR"
# Calculate offset
OFFSET=$(( (BATCH_NUM - 1) * BATCH_SIZE ))
# Process batch
find "$DATA_DIR" -name "*.csv" | sort | tail -n +$((OFFSET + 1)) | head -$BATCH_SIZE | while read file; do
FILENAME=$(basename "$file")
OUTPUT="$OUTPUT_DIR/${FILENAME%.csv}.json"
echo "Processing: $FILENAME"
process_csv_to_json "$file" > "$OUTPUT"
echo "✓ Created: $OUTPUT"
done
# Report progress
TOTAL=$(find "$DATA_DIR" -name "*.csv" | wc -l)
PROCESSED=$(find "$OUTPUT_DIR" -name "*.json" | wc -l)
echo ""
echo "Batch $BATCH_NUM complete"
echo "Progress: $PROCESSED/$TOTAL files"
if [ $PROCESSED -lt $TOTAL ]; then
NEXT_BATCH=$((BATCH_NUM + 1))
echo "Next: ./script.sh $NEXT_BATCH"
else
echo "🎉 All files processed!"
fi
示例 3:受 API 速率限制的抓取
#!/bin/bash
# Scrape API with rate limits and timeouts
API_IDS="ids.txt"
OUTPUT_DIR="api_data"
CHECKPOINT=".api_checkpoint"
mkdir -p "$OUTPUT_DIR"
# Load last checkpoint
LAST_ID=$(cat "$CHECKPOINT" 2>/dev/null || echo "0")
# Process next 10 IDs
grep -A 10 "^$LAST_ID$" "$API_IDS" | tail -n +2 | head -10 | while read id; do
echo "Fetching ID: $id"
# API call with timeout
if timeout 30s curl -s "https://api.example.com/data/$id" > "$OUTPUT_DIR/$id.json"; then
echo "$id" > "$CHECKPOINT"
echo "✓ Saved: $id.json"
else
echo "✗ Failed: $id"
fi
# Rate limiting (100ms between requests)
sleep 0.1
done
# Progress
TOTAL=$(wc -l < "$API_IDS")
COMPLETED=$(find "$OUTPUT_DIR" -name "*.json" | wc -l)
echo ""
echo "Progress: $COMPLETED/$TOTAL IDs"
[ $COMPLETED -lt $TOTAL ] && echo "Run again to continue"
与 Claude Code 集成
多轮工作流
不要一次执行一个长操作,而是将其拆分到多轮 Claude Code 调用中:
第 1 轮:
Process first batch of 10 items and save checkpoint
第 2 轮:
Resume from checkpoint and process next 10 items
第 3 轮:
Complete processing and generate final report
状态检查模式
# Turn 1: Start background job
./long_operation.sh > output.log 2>&1 &
echo $! > pid.txt
echo "Started background job (PID: $(cat pid.txt))"
# Turn 2: Check status
if ps -p $(cat pid.txt) > /dev/null 2>&1; then
echo "Still running..."
echo "Recent output:"
tail -20 output.log
else
echo "✓ Complete!"
cat output.log
rm pid.txt
fi
最佳实践
✅ 应该做
- 将操作分块为每批 5-10 项
- 保存检查点,每完成一项或一批后保存
- 为单项操作设置超时(最长 60-90 秒)
- 清晰、频繁地报告进度
- 支持从任意检查点恢复
- 合理并行处理(最多 3-5 个并发任务)
- 将失败项与成功项分开跟踪
- 完成后清理检查点文件
❌ 不应该做
- 不要一次处理所有内容(超过 50 项)
- 长工作流中不要跳过检查点
- 不要忽略超时信号(处理 EXIT 124)
- 不要在没有进度更新的情况下无限期阻塞
- 不要过度并行(会造成资源问题)
- 不要因缺少状态信息而丢失进度
- 不要无限重试(最多重试 3-4 次)
- 不要忘记清理临时文件
快速参考
# Batch processing
tail -n +$OFFSET file.txt | head -$BATCH_SIZE | while read item; do process; done
# Checkpoint resume
LAST=$(cat .checkpoint || echo 0); process_from $LAST
# State machine
case $(cat .state) in PHASE1) step1 ;; PHASE2) step2 ;; esac
# Progress tracking
echo "Progress: $COMPLETED/$TOTAL ($((COMPLETED * 100 / TOTAL))%)"
# Timeout with fallback
timeout 90s operation || use_cached_result
# Parallel with limit
for i in items; do process &; jobs=$(jobs -r | wc -l); [ $jobs -ge $MAX ] && wait -n; done
版本:1.0.0 作者:整理自超时预防技能模式 最后更新:2025-11-18 许可证:MIT 核心原则:切勿试图一次完成所有事情——分块处理、设置检查点并恢复执行。
评论
支持 Markdown