Files
openclaw-backups/skills/openclaw-self-healing/docs/auto-retry-integration.md

10 KiB
Raw Blame History

Auto-Retry System (Level 1) 통합 가이드

작성일: 2026-02-05 상태: 테스트 완료, 실전 배포 가능

테스트 결과

🔄 Auto-Retry Demo
Simulating unreliable API (fails 2x, succeeds on 3rd)...

  → Attempt 1... ❌ Timeout
  ⚠️  Retry 1 (waiting 500ms)

  → Attempt 2... ❌ Timeout
  ⚠️  Retry 2 (waiting 1000ms)

  → Attempt 3... ✅ Success!

✅ Final Success!
   Total attempts: 3
   Total duration: 1504ms

Loop가 닫혔습니다! 🎯

  • 실패 감지 → 자동 재시도 → 성공
  • 사람 개입 없음

핵심 기능

1. 검증 가능한 결과 기반

// 자동 판단
 Exit code 0 = 성공
 ETIMEDOUT = 재시도 가능
 HTTP 429 = Rate limit, 재시도 가능
 HTTP 400 = Bad request, 재시도 불가 (즉시 실패)

2. 지능적 백오프

// Exponential backoff
Attempt 1: 즉시
Attempt 2: 1 대기
Attempt 3: 2 대기
Attempt 4: 4 대기
Attempt 5: 8 대기

3. 자동 로깅

# ~/openclaw/logs/auto-retry.jsonl
{"timestamp":"2026-02-05T04:38:39Z","type":"failure","attempts":3,...}

4. Discord 알림 (선택)

재시도 중 → 성공/실패 알림

실제 통합 방법

A. 기존 Cron 래핑 (가장 간단)

Before:

// 기존 코드 (재시도 없음)
async function monitorTQQQ() {
  const price = await fetchStockPrice('TQQQ');
  const rate = await getExchangeRate();
  return { price, rate };
}

// Cron에서 직접 호출
const result = await monitorTQQQ();

After:

const { executeWithRetry } = require('~/openclaw/lib/auto-retry');

// 코드 변경 없음! 그냥 래핑만
const result = await executeWithRetry(
  monitorTQQQ,  // 기존 함수 그대로
  { maxRetries: 3, backoff: 'exponential' }
);

변경량: 2줄 추가 효과: 일시적 에러 자동 복구

B. Discord 알림 포함

const { executeWithNotifications } = require('~/openclaw/lib/auto-retry');

const result = await executeWithNotifications(
  monitorTQQQ,
  {
    maxRetries: 3,
    backoff: 'exponential',
    discordWebhook: WEBHOOK_URL,
    taskName: 'TQQQ 15분 모니터링'
  }
);

효과: 재시도 중/성공/실패 자동 알림

C. 개별 API 호출 래핑 (더 세밀)

const { executeWithRetry } = require('~/openclaw/lib/auto-retry');

async function monitorTQQQ() {
  // 각 API 호출마다 재시도
  const price = await executeWithRetry(
    () => fetchStockPrice('TQQQ'),
    { maxRetries: 3 }
  );

  const rate = await executeWithRetry(
    () => getExchangeRate(),
    { maxRetries: 3 }
  );

  return {
    price: price.result,
    rate: rate.result
  };
}

효과: 개별 API 실패해도 다른 것은 계속 진행

실전 예시

예시 1: TQQQ 15분 모니터링

파일: ~/openclaw/cron-scripts/tqqq-monitor.js

const { executeWithNotifications } = require('../lib/auto-retry');

async function main() {
  const WEBHOOK = 'https://discord.com/api/webhooks/.../...';

  // 기존 모니터링 로직
  async function monitor() {
    const yf = require('yahoo-finance2');

    const quote = await yf.quote('TQQQ');
    const price = quote.regularMarketPrice;

    // ... 나머지 로직

    return { price, /* ... */ };
  }

  // 자동 재시도 래핑
  try {
    const result = await executeWithNotifications(
      monitor,
      {
        maxRetries: 3,
        backoff: 'exponential',
        discordWebhook: WEBHOOK,
        taskName: 'TQQQ 15분 모니터링',
        context: {
          cron: 'tqqq-15min',
          schedule: '*/15 * * * *'
        }
      }
    );

    console.log('✅ Success:', result.result);

  } catch (error) {
    console.error('❌ Failed after retries:', error.message);
    process.exit(1);
  }
}

main();

Cron 메시지에서:

node ~/openclaw/cron-scripts/tqqq-monitor.js

(재시도는 스크립트 내부에서 자동 처리)

예시 2: Trend Hunter (복잡한 작업)

const { executeWithRetry } = require('../lib/auto-retry');

async function trendHunter() {
  // 각 데이터 소스마다 개별 재시도
  const [hn, reddit, arxiv] = await Promise.all([
    executeWithRetry(() => fetchHackerNews(), { maxRetries: 2 }),
    executeWithRetry(() => fetchReddit(), { maxRetries: 2 }),
    executeWithRetry(() => fetchArxiv(), { maxRetries: 2 })
  ]);

  // 하나 실패해도 다른 것으로 분석 가능
  const trends = analyzeTrends([
    hn.result || [],
    reddit.result || [],
    arxiv.result || []
  ]);

  return trends;
}

// 전체를 한 번 더 래핑 (이중 보호)
const result = await executeWithRetry(trendHunter, { maxRetries: 1 });

예시 3: GitHub Watcher (Shell 스크립트)

파일: ~/openclaw/skills/github-watcher/check-with-retry.sh

#!/bin/bash

# Node.js wrapper로 실행
node -e "
const { executeWithRetry } = require('$HOME/openclaw/lib/auto-retry');
const { exec } = require('child_process');

executeWithRetry(
  () => new Promise((resolve, reject) => {
    exec('$HOME/openclaw/skills/github-watcher/check.sh', (error, stdout) => {
      if (error) reject(error);
      else resolve(stdout);
    });
  }),
  { maxRetries: 2 }
).then(r => console.log(r.result))
  .catch(e => { console.error(e); process.exit(1); });
"

설정 옵션

maxRetries (기본: 3)

{ maxRetries: 5 }  // 최대 5회 재시도

권장:

  • 빠른 API: 2-3회
  • 느린 작업: 3-5회
  • 중요한 작업: 5-10회

backoff (기본: 'exponential')

{ backoff: 'exponential' }  // 1s, 2s, 4s, 8s...
{ backoff: 'linear' }       // 1s, 2s, 3s, 4s...
{ backoff: 'fixed' }        // 1s, 1s, 1s, 1s...

권장:

  • Rate limit 위험: exponential
  • 네트워크 지연: linear
  • 빠른 재시도: fixed (baseDelay 작게)

baseDelay (기본: 1000ms)

{ baseDelay: 500 }   // 빠른 재시도 (0.5초)
{ baseDelay: 2000 }  // 느린 재시도 (2초)

콜백

{
  onRetry: (attempt, error, analysis, delay) => {
    // 재시도할 때마다 호출
    console.log(`Retry ${attempt}: ${error.message}`);
  },

  onSuccess: (attempt, result) => {
    // 성공 시 호출
    if (attempt > 1) {
      console.log(`Recovered after ${attempt} attempts`);
    }
  },

  onFinalFailure: (attempts, analysis) => {
    // 최종 실패 시 호출
    console.error(`Failed after ${attempts.length} attempts`);
    console.error(`Suggestion: ${analysis.suggestedFix}`);
  }
}

로그 분석

로그 위치

~/openclaw/logs/auto-retry.jsonl

로그 형식 (JSONL)

{
  "timestamp": "2026-02-05T04:38:39Z",
  "type": "failure",
  "context": { "task": "fetch TQQQ price" },
  "attempts": [
    { "attempt": 1, "success": false, "duration": 465, "error": {...} },
    { "attempt": 2, "success": false, "duration": 214, "error": {...} },
    { "attempt": 3, "success": false, "duration": 114, "error": {...} }
  ],
  "totalDuration": 3796,
  "finalError": {
    "type": "Error",
    "message": "HTTP 429",
    "category": "http",
    "suggestedFix": "Rate limit exceeded - increase backoff delay"
  }
}

분석 예시

# 최근 실패 확인
tail -50 ~/openclaw/logs/auto-retry.jsonl | grep '"type":"failure"'

# 재시도가 가장 많았던 작업
jq -r 'select(.type=="success") | "\(.attempts | length) \(.context.task)"' \
  ~/openclaw/logs/auto-retry.jsonl | sort -rn | head -10

# 가장 흔한 에러
jq -r '.finalError.message' ~/openclaw/logs/auto-retry.jsonl | sort | uniq -c | sort -rn

점진적 도입 계획

Week 1: 시범 적용 (3개 cron)

  • TQQQ 15분 모니터링
  • GitHub Watcher
  • Market Volatility

목표: 재시도 작동 확인

Week 2: 확대 (10개 cron)

  • 모든 외부 API 호출하는 cron
  • 네트워크 의존성 있는 cron

목표: 로그 분석, 설정 최적화

Week 3: 전체 적용 (23개 cron)

  • 모든 cron에 적용
  • Discord 알림 활성화

목표: 완전 자동화

효과 측정

측정 지표

  1. 재시도 성공률

    # 재시도 후 성공한 비율
    성공 with attempts > 1 / 전체 재시도 건수
    
  2. 에러 감소율

    # 자동 복구로 줄어든 에러
    (재시도 성공 건수 / 전체 실행 건수) × 100%
    
  3. 평균 복구 시간

    # 재시도로 복구까지 걸린 평균 시간
    avg(totalDuration) for successful retries
    

예상 효과

Before (재시도 없음):

100회 실행
→ 10회 일시적 에러 (네트워크, 타임아웃 등)
→ 사람이 수동으로 재실행
→ 에러율: 10%

After (자동 재시도):

100회 실행
→ 10회 일시적 에러
→ 9회 자동 복구 (재시도 성공)
→ 1회만 최종 실패
→ 에러율: 1% (90% 감소!)

다음 단계 (Level 2)

Level 1이 안정화되면:

Level 2: 파라미터 자동 조정

  • 로그 분석 → 최적 설정 자동 제안
  • 예: "TQQQ는 항상 2회 재시도 필요 → maxRetries 3으로 고정"

Level 3: AI 코드 수정

  • 반복 패턴 감지 → AI가 근본 원인 수정

FAQ

Q: 모든 에러를 재시도하나요?

A: 아니요. 재시도 가능한 에러만.

  • 재시도: ETIMEDOUT, ECONNRESET, HTTP 429/500/502/503
  • 재시도 안 함: HTTP 400/401/403/404, ENOENT

Q: 무한 재시도 위험은?

A: maxRetries로 제한. 기본 3회.

Q: 기존 코드 수정 필요한가요?

A: 최소한만. 함수 래핑만 하면 됨.

Q: 성능 영향은?

A:

  • 성공 시: 거의 없음 (<1ms 오버헤드)
  • 재시도 시: backoff 대기 시간만큼

Q: Discord 알림이 너무 많지 않나요?

A: 선택 사항. executeWithRetry 쓰면 알림 없음.

파일 목록

~/openclaw/
├── lib/
│   └── auto-retry.js             (핵심 로직)
├── examples/
│   ├── auto-retry-usage.js       (사용 예시)
│   └── demo-retry.js             (데모)
├── logs/
│   └── auto-retry.jsonl          (자동 생성)
└── docs/
    └── auto-retry-integration.md (이 문서)

지금 바로 시작

# 1. 테스트
node ~/openclaw/examples/demo-retry.js

# 2. 실제 사용
const { executeWithRetry } = require('~/openclaw/lib/auto-retry');

// 3. 기존 함수 래핑
const result = await executeWithRetry(yourFunction, { maxRetries: 3 });

# 4. 로그 확인
tail -f ~/openclaw/logs/auto-retry.jsonl

상태: 프로덕션 준비 완료 테스트: 통과 문서: 완료 다음: Cron에 적용