AI 서비스 운영에서 버전 관리는 선택이 아닌 필수입니다. 모델 업데이트, 프롬프트 변경, 또는 새로운 기능 배포 후 예기치 않은 문제가 발생하면 빠른 롤백이 수익과 신뢰를 지키는 마지막 방어선입니다. 이번 튜토리얼에서는 HolySheep AI를 활용한 실전 롤백 아키텍처를 단계별로 설계하겠습니다.
실제 사용 사례: 롤백이 필요한 순간들
사례 1: 이커머스 AI 고객 서비스 급증
저는 지난 블랙프라이드 기간 중 AI 고객 서비스 챗봇을 GPT-4에서 새로운 모델로 마이그레이션한 경험이 있습니다. 트래픽이 평소의 15배로 급증하는 상황에서 새 모델이 예상보다 높은 토큰 소비를 보여 예산 초과 위험에 처했습니다. 롤백 없이는 수백만 원의 추가 비용이 발생할 뻔했습니다.
사례 2: 기업 RAG 시스템 출시
엔터프라이즈 고객을 위한 RAG 기반 지식 검색 시스템을 배포한 날, 특정 산업 용어에서 검색 정확도가 40% 하락하는 문제가 발생했습니다. 클라이언트 니즈에 맞춰 프롬프트를 최적화한 직후였고, 즉시 이전 버전으로 복원해야 했습니다.
사례 3: 개인 개발자 프로젝트
사이드 프로젝트로 운영하는 AI 번역 서비스에서 모델 업데이트 후 반응 시간(latency)이 3초에서 8초로 증가하는 문제가 생겼습니다. 작은 프로젝트였지만 사용자 이탈이 급격히 발생했고, 롤백 없이는 서비스 종료로 이어질 뻔했습니다.
버전 롤백 아키텍처 핵심 설계
효과적인 롤백 시스템은 다음 네 가지 요소를 기반으로 설계해야 합니다:
- 구성 기반 모델 전환: 환경 변수로 모델 선택
- 지연 시간 모니터링: 실시간 성능 추적
- 비용 임계치 알림: 예산 초과 방지
- 그레이스풀 디그레이션: 점진적 트래픽 전환
HolySheep AI 기반 롤백 구현
HolySheep AI의 단일 API 키로 여러 모델을 연결하는 특성을 활용하면, 롤백 시 별도 설정 변경 없이 다른 모델로 즉시 전환할 수 있습니다. 아래는 Python 기반의 완전한 롤백 시스템 구현입니다.
1단계: 롤백 매니저 클래스 구현
import os
import time
import json
import logging
from datetime import datetime
from enum import Enum
from typing import Optional, Dict, Any, List
from dataclasses import dataclass, field
from holySheep_client import HolySheepAIClient
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class ModelVersion(Enum):
"""사용 가능한 모델 버전 정의"""
PRIMARY = "gpt-4.1"
FALLBACK = "claude-sonnet-4-20250514"
EMERGENCY = "gemini-2.5-flash"
ECONOMY = "deepseek-v3.2"
@dataclass
class VersionConfig:
"""버전별 구성 정보"""
name: str
model: str
max_tokens: int = 4096
temperature: float = 0.7
max_cost_per_request: float = 0.50
max_latency_ms: int = 3000
weight: int = 100
@dataclass
class HealthMetrics:
"""헬스 메트릭 데이터"""
timestamp: datetime
latency_ms: float
error_rate: float
cost_per_request: float
success_count: int = 0
failure_count: int = 0
class RollbackManager:
"""
AI 서비스 버전 롤백 관리자
주요 기능:
- 모델별 건강 상태 모니터링
- 자동/수동 롤백 트리거
- 비용 및 지연 시간 기반 알림
- 버전 히스토리 추적
"""
def __init__(self, api_key: str):
self.client = HolySheepAIClient(api_key=api_key)
self.base_url = "https://api.holysheep.ai/v1"
# 버전 구성 정의
self.versions: Dict[str, VersionConfig] = {
"production": VersionConfig(
name="production",
model=ModelVersion.PRIMARY.value,
max_tokens=4096,
temperature=0.7,
max_cost_per_request=0.50,
max_latency_ms=3000,
weight=100
),
"fallback": VersionConfig(
name="fallback",
model=ModelVersion.FALLBACK.value,
max_tokens=4096,
temperature=0.7,
max_cost_per_request=0.75,
max_latency_ms=4000,
weight=0
),
"emergency": VersionConfig(
name="emergency",
model=ModelVersion.EMERGENCY.value,
max_tokens=8192,
temperature=0.5,
max_cost_per_request=0.25,
max_latency_ms=2000,
weight=0
),
"economy": VersionConfig(
name="economy",
model=ModelVersion.ECONOMY.value,
max_tokens=4096,
temperature=0.6,
max_cost_per_request=0.15,
max_latency_ms=3500,
weight=0
)
}
self.current_version = "production"
self.health_history: List[HealthMetrics] = []
self.rollback_history: List[Dict[str, Any]] = []
def execute_rollback(self, target_version: str, reason: str) -> bool:
"""指定バージョンへのロールバック実行"""
if target_version not in self.versions:
logger.error(f"알 수 없는 버전: {target_version}")
return False
old_version = self.current_version
self.current_version = target_version
# 버전 가중치 조정
self.versions[old_version].weight = 0
self.versions[target_version].weight = 100
# 롤백 히스토리 기록
rollback_record = {
"timestamp": datetime.now().isoformat(),
"from_version": old_version,
"to_version": target_version,
"reason": reason,
"previous_metrics": self.health_history[-1].__dict__ if self.health_history else None
}
self.rollback_history.append(rollback_record)
logger.info(f"롤백 완료: {old_version} → {target_version}")
logger.info(f"롤백 사유: {reason}")
return True
def check_health_and_auto_rollback(self) -> Optional[str]:
"""헬스 체크 및 자동 롤백 필요성 판단"""
if not self.health_history:
return None
latest = self.health_history[-1]
current_config = self.versions[self.current_version]
# 지연 시간 초과 체크
if latest.latency_ms > current_config.max_latency_ms:
logger.warning(
f"지연 시간 임계치 초과: {latest.latency_ms}ms > {current_config.max_latency_ms}ms"
)
return f"지연 시간 초과: {latest.latency_ms}ms"
# 비용 초과 체크
if latest.cost_per_request > current_config.max_cost_per_request:
logger.warning(
f"비용 임계치 초과: ${latest.cost_per_request:.4f} > ${current_config.max_cost_per_request:.4f}"
)
return f"비용 초과: ${latest.cost_per_request:.4f}"
# 오류율 체크 (5% 이상)
if latest.error_rate > 0.05:
logger.warning(f"오류율 임계치 초과: {latest.error_rate:.2%}")
return f"오류율 초과: {latest.error_rate:.2%}"
return None
def send_request(self, prompt: str, system_prompt: str = "") -> Dict[str, Any]:
"""롤백 가능한 요청 전송"""
start_time = time.time()
current_config = self.versions[self.current_version]
try:
response = self.client.chat.completions.create(
model=current_config.model,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
],
max_tokens=current_config.max_tokens,
temperature=current_config.temperature
)
latency_ms = (time.time() - start_time) * 1000
usage = response.usage
# 토큰 기반 비용 계산
cost = self._calculate_cost(current_config.model, usage)
# 메트릭 기록
metric = HealthMetrics(
timestamp=datetime.now(),
latency_ms=latency_ms,
error_rate=0.0,
cost_per_request=cost,
success_count=1,
failure_count=0
)
self.health_history.append(metric)
# 자동 롤백 체크 (최근 10개 요청 기준)
if len(self.health_history) >= 10:
if self._should_auto_rollback():
reason = self.check_health_and_auto_rollback()
if reason and self.current_version != "fallback":
self.execute_rollback("fallback", reason)
return {
"content": response.choices[0].message.content,
"model": current_config.model,
"latency_ms": latency_ms,
"cost": cost,
"version": self.current_version
}
except Exception as e:
latency_ms = (time.time() - start_time) * 1000
# 메트릭 기록
metric = HealthMetrics(
timestamp=datetime.now(),
latency_ms=latency_ms,
error_rate=1.0,
cost_per_request=0.0,
success_count=0,
failure_count=1
)
self.health_history.append(metric)
# 자동 롤백 트리거
if self.current_version != "emergency":
self.execute_rollback("emergency", f"예외 발생: {str(e)}")
raise
def _calculate_cost(self, model: str, usage) -> float:
"""토큰 사용량 기반 비용 계산 (HolySheep AI 가격표)"""
pricing = {
"gpt-4.1": {"input": 0.08, "output": 0.32}, # $8/MTok 입력, $32/MTok 출력
"claude-sonnet-4-20250514": {"input": 0.015, "output": 0.075}, # $15/MTok (양방향)
"gemini-2.5-flash": {"input": 0.0025, "output": 0.010}, # $2.50/MTok 입력
"deepseek-v3.2": {"input": 0.00042, "output": 0.0021}, # $0.42/MTok 입력
}
p = pricing.get(model, {"input": 0.01, "output": 0.03})
total_tokens = usage.prompt_tokens + usage.completion_tokens
# 단순화된 계산 (실제 사용량 반영)
return (usage.prompt_tokens * p["input"] +
usage.completion_tokens * p["output"]) / 1000
def _should_auto_rollback(self) -> bool:
"""최근 10개 요청 기반 자동 롤백 판단"""
recent = self.health_history[-10:]
avg_latency = sum(m.latency_ms for m in recent) / 10
avg_cost = sum(m.cost_per_request for m in recent) / 10
avg_error_rate = sum(m.error_rate for m in recent) / 10
current_config = self.versions[self.current_version]
# 3개 지표 중 2개 이상 임계치 초과 시 롤백
violations = 0
if avg_latency > current_config.max_latency_ms:
violations += 1
if avg_cost > current_config.max_cost_per_request:
violations += 1
if avg_error_rate > 0.05:
violations += 1
return violations >= 2
def get_status_report(self) -> Dict[str, Any]:
"""현재 상태 리포트 생성"""
recent = self.health_history[-10:] if len(self.health_history) >= 10 else self.health_history
return {
"current_version": self.current_version,
"current_model": self.versions[self.current_version].model,
"total_requests": len(self.health_history),
"recent_avg_latency_ms": sum(m.latency_ms for m in recent) / len(recent) if recent else 0,
"recent_avg_cost": sum(m.cost_per_request for m in recent) / len(recent) if recent else 0,
"recent_avg_error_rate": sum(m.error_rate for m in recent) / len(recent) if recent else 0,
"rollback_count": len(self.rollback_history),
"available_versions": list(self.versions.keys())
}
2단계: HolySheep AI 클라이언트 래퍼 구현
import requests
from typing import List, Dict, Any, Optional
from openai import OpenAI
class HolySheepAIClient:
"""
HolySheep AI API 래퍼 클래스
HolySheep AI 공식 엔드포인트 사용
단일 API 키로 GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2 통합
"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
# OpenAI 호환 클라이언트로 HolySheep API 호출
self.client = OpenAI(
api_key=self.api_key,
base_url=self.base_url
)
def chat_complete(self,
model: str,
messages: List[Dict[str, str]],
**kwargs) -> Dict[str, Any]:
"""채팅 완성 API 호출"""
response = self.client.chat.completions.create(
model=model,
messages=messages,
**kwargs
)
return response
실제 사용 예시
def main():
# HolySheep AI API 키 설정
api_key = "YOUR_HOLYSHEEP_API_KEY" # HolySheep에서 발급받은 키로 교체
# 롤백 매니저 초기화
manager = RollbackManager(api_key)
print("=== HolySheep AI 롤백 시스템 테스트 ===")
print(f"현재 버전: {manager.current_version}")
print(f"사용 모델: {manager.versions[manager.current_version].model}")
print()
# 테스트 요청 실행
test_prompts = [
"안녕하세요, AI 서비스 상태를 확인해주세요.",
"한국의 주요 관광지에 대해 설명해주세요.",
"최신 소프트웨어 개발 트렌드를 알려주세요."
]
for i, prompt in enumerate(test_prompts):
print(f"\n--- 요청 {i+1} ---")
print(f"프롬프트: {prompt}")
try:
result = manager.send_request(
prompt=prompt,
system_prompt="당신은 도움이 되는 AI 어시스턴트입니다."
)
print(f"응답 모델: {result['model']}")
print(f"지연 시간: {result['latency_ms']:.2f}ms")
print(f"비용: ${result['cost']:.6f}")
print(f"버전: {result['version']}")
except Exception as e:
print(f"오류 발생: {str(e)}")
# 상태 리포트 출력
print("\n" + "="*50)
print("=== 최종 상태 리포트 ===")
status = manager.get_status_report()
for key, value in status.items():
if isinstance(value, float):
print(f"{key}: {value:.4f}")
else:
print(f"{key}: {value}")
# 롤백 히스토리 출력
if manager.rollback_history:
print("\n=== 롤백 히스토리 ===")
for record in manager.rollback_history:
print(f"시간: {record['timestamp']}")
print(f"변경: {record['from_version']} → {record['to_version']}")
print(f"사유: {record['reason']}")
print()
if __name__ == "__main__":
main()
실전 배포 스크립트: Kubernetes 기반 블루-그린 배포
#!/bin/bash
AI 서비스 블루-그린 배포 및 롤백 스크립트
HolySheep AI API 기반 서비스용
set -e
설정
NAMESPACE="ai-services"
SERVICE_NAME="ai-chatbot"
HOLYSHEEP_API_KEY="${HOLYSHEEP_API_KEY}"
REGISTRY="ghcr.io/your-org"
색상 출력
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
헬스 체크 함수
check_health() {
local endpoint=$1
local timeout=${2:-30}
local start_time=$(date +%s)
while true; do
local current_time=$(date +%s)
local elapsed=$((current_time - start_time))
if [ $elapsed -gt $timeout ]; then
log_error "헬스 체크 타임아웃: ${timeout}초"
return 1
fi
if curl -sf "${endpoint}/health" > /dev/null 2>&1; then
log_info "헬스 체크 통과"
return 0
fi
log_warn "헬스 체크 대기 중... (${elapsed}/${timeout}초)"
sleep 2
done
}
메트릭 수집 및 롤백 판단
evaluate_rollback_criteria() {
local version=$1
local avg_latency=$(kubectl get pods -n $NAMESPACE -l version=$version \
-o jsonpath='{.items[*].metadata.labels.avg_latency_ms}')
local error_rate=$(kubectl get pods -n $NAMESPACE -l version=$version \
-o jsonpath='{.items[*].metadata.labels.error_rate}')
local cost_per_req=$(kubectl get pods -n $NAMESPACE -l version=$version \
-o jsonpath='{.items[*].metadata.labels.cost_per_request}')
# HolySheep AI 기준 임계치
MAX_LATENCY=3000
MAX_ERROR_RATE=0.05
MAX_COST=0.50
log_info "메트릭 평가 중..."
log_info " 평균 지연: ${avg_latency}ms (임계치: ${MAX_LATENCY}ms)"
log_info " 오류율: ${error_rate} (임계치: ${MAX_ERROR_RATE})"
log_info " 요청당 비용: \$${cost_per_req} (임계치: \$${MAX_COST})"
# 롤백 조건 체크
if (( $(echo "$avg_latency > $MAX_LATENCY" | bc -l) )) || \
(( $(echo "$error_rate > $MAX_ERROR_RATE" | bc -l) )) || \
(( $(echo "$cost_per_req > $MAX_COST" | bc -l) )); then
log_warn "롤백 조건 충족"
return 0
else
log_info "모든 지표 정상 범위"
return 1
fi
}
블루-그린 배포 실행
deploy_blue_green() {
local new_version=$1
local weight=${2:-10}
log_info "블루-그린 배포 시작: v${new_version}"
# 새 버전 디플로이먼트를 기존와 분리하여 생성
cat <롤백 실행
rollback_to_version() {
local target_version=$1
local reason=${2:-"Manual rollback"}
log_warn "롤백 시작: → v${target_version}"
log_info "롤백 사유: ${reason}"
# 현재 메트릭 기록
kubectl annotate deployment ${SERVICE_NAME}-$(kubectl get deployments -n $NAMESPACE \
-o jsonpath='{.items[*].metadata.labels.version}') \
-n $NAMESPACE \
rollback-reason="${reason}" \
rollback-timestamp="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# 100% 트래픽 이전
kubectl patch virtualservice ${SERVICE_NAME} -n ${NAMESPACE} \
--type='json' \
-p="[{\"op\":\"replace\",\"path\":\"/spec/http/0/routes/0/weight\",\"value\":100},{\"op\":\"replace\",\"path\":\"/spec/http/0/routes/1/weight\",\"value\":0}]"
log_info "트래픽 100% v${target_version}로 전환 완료"
# 롤백 히스토리 기록
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ),v${target_version},${reason}" >> /var/log/rollback-history.csv
}
메인 실행
case "${1:-deploy}" in
deploy)
deploy_blue_green "${2:-2}" "${3:-10}"
;;
rollback)
rollback_to_version "${2:-1}" "${3:-Manual}"
;;
health-check)
check_health "http://${SERVICE_NAME}.${NAMESPACE}.svc.cluster.local" "${3:-30}"
;;
evaluate)
evaluate_rollback_criteria "${2:-current}"
;;
*)
echo "Usage: $0 {deploy|rollback|health-check|evaluate} [version] [options]"
exit 1
;;
esac
모니터링 대시보드 설정
효과적인 롤백 판단을 위해서는 실시간 모니터링이 필수입니다. Prometheus와 Grafana를 활용한 모니터링 설정 예시입니다.
# prometheus-rules.yml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: ai-service-rollback-rules
namespace: ai-services
spec:
groups:
- name: ai-service-rollback
interval: 30s
rules:
# 지연 시간警报
- alert: AILatencyHigh
expr: histogram_quantile(0.95, rate(ai_request_duration_seconds_bucket[5m])) > 3
for: 2m
labels:
severity: warning
annotations:
summary: "AI 요청 지연 시간 임계치 초과"
description: "95번째 백분위 지연 시간: {{ $value }}초 (임계치: 3초)"
runbook_url: "https://wiki.example.com/runbooks/ai-latency-high"
# 비용警报
- alert: AIRequestCostHigh
expr: rate(ai_request_cost_total[1h]) / rate(ai_request_count_total[1h]) > 0.50
for: 5m
labels:
severity: critical
annotations:
summary: "AI 요청 비용 임계치 초과"
description: "평균 요청 비용: ${{ $value }} (임계치: $0.50)"
runbook_url: "https://wiki.example.com/runbooks/ai-cost-high"
# 오류율警报
- alert: AIErrorRateHigh
expr: rate(ai_request_errors_total[5m]) / rate(ai_request_count_total[5m]) > 0.05
for: 3m
labels:
severity: critical
annotations:
summary: "AI 요청 오류율 임계치 초과"
description: "오류율: {{ $value | humanizePercentage }} (임계치: 5%)"
runbook_url: "https://wiki.example.com/runbooks/ai-error-rate-high"
# HolySheep API 연결 실패警报
- alert: HolySheepAPIConnectionFailed
expr: rate(holysheep_connection_errors_total[5m]) > 0
for: 1m
labels:
severity: critical
annotations:
summary: "HolySheep AI API 연결 실패"
description: "HolySheep API 연결 오류 발생: {{ $value }}회/5분"
# 자동 롤백 추천
- alert: AIRollbackRecommended
expr: |
(histogram_quantile(0.95, rate(ai_request_duration_seconds_bucket[5m])) > 3) and
(rate(ai_request_cost_total[1h]) / rate(ai_request_count_total[1h]) > 0.50)
for: 5m
labels:
severity: critical
action: auto-rollback
annotations:
summary: "자동 롤백 권장"
description: "지연 시간과 비용 모두 임계치 초과. 자동 롤백 실행을 권장합니다."
runbook_url: "https://wiki.example.com/runbooks/ai-auto-rollback"
비용 최적화: HolySheep AI 모델별 비용 비교
| 모델 | 입력 비용 ($/MTok) | 출력 비용 ($/MTok) | 적용 시나리오 | 평균 지연 시간 |
|---|---|---|---|---|
| GPT-4.1 | $8.00 | $32.00 | 고품질 복잡한 작업 | 800-1200ms |
| Claude Sonnet 4.5 | $15.00 | $75.00 | 긴 컨텍스트 처리 | 900-1400ms |
| Gemini 2.5 Flash | $2.50 | $10.00 | 빠른 응답, 비용 효율 | 400-700ms |
| DeepSeek V3.2 | $0.42 | $2.10 | 대량 처리, Economical | 600-1000ms |
자주 발생하는 오류와 해결책
오류 1: 롤백 후에도 이전 버전에서 발생했던 문제가 지속되는 경우
증상: 롤백을 실행했음에도 동일한 오류나 성능 저하가 계속 발생합니다.
원인 분석:
- 데이터베이스 상태가 이미 손상됨
- 롤백 스크립트에서 환경 변수 미적용
- 캐시 레이어에 이전 버전 데이터 남아있음
해결 코드:
# 롤백 후 전체 상태 초기화 스크립트
def full_state_reset_after_rollback():
"""롤백 후 완전한 상태 초기화"""
# 1. Redis 캐시 플러시
redis_client = Redis(host='redis.default.svc.cluster.local', port=6379)
redis_client.flushdb()
logger.info("Redis 캐시 플러시 완료")
# 2. 메트릭 히스토리 초기화 ( 롤백 시점부터 다시 시작)
health_history.clear()
logger.info("헬스 히스토리 초기화 완료")
# 3. 환경 변수 강제 리로드
current_config = versions[current_version]
os.environ['MODEL_VERSION'] = current_config.name
os.environ['MODEL_ENDPOINT'] = f"{base_url}/chat/completions"
os.environ['MAX_TOKENS'] = str(current_config.max_tokens)
os.environ['TEMPERATURE'] = str(current_config.temperature)
# 4. 커넥션 풀 리셋
client.close()
time.sleep(2)
client = OpenAI(api_key=api_key, base_url=base_url)
logger.info("API 커넥션 풀 리셋 완료")
# 5. Kubernetes 환경 변수 리로드 트리거
subprocess.run([
'kubectl', 'rollout', 'restart',
f'deployment/{service_name}', '-n', namespace
])
logger.info("Kubernetes Pod 리스타트 완료")
return True
오류 2: HolySheep API 연결 타임아웃으로 인한 롤백 무한 루프
증상: HolySheep API 연결이 불안정할 때 롤백이 계속 트리거되어 서비스가 정상 동작하지 않습니다.
원인 분석:
- 회로 차단기(circuit breaker) 패턴 미구현
- 연속 실패 횟수 기반 롤백 로직 부재
- API 일시적 장애를 영구 장애로 판단
해결 코드:
import time
from threading import Lock
from enum import Enum
class CircuitState(Enum):
CLOSED = "closed" # 정상 동작
OPEN = "open" # 차단됨
HALF_OPEN = "half_open" # 테스트 중
class CircuitBreaker:
"""회로 차단기: API 일시 장애 시 무한 롤백 방지"""
def __init__(self,
failure_threshold: int = 5,
recovery_timeout: int = 60,
success_threshold: int = 3):
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.success_threshold = success_threshold
self.failure_count = 0
self.success_count = 0
self.last_failure_time = None
self.state = CircuitState.CLOSED
self.lock = Lock()
def call(self, func, *args, **kwargs):
"""회로 차단기 보호 함수 호출"""
with self.lock:
if self.state == CircuitState.OPEN:
# recovery_timeout 경과 확인
if time.time() - self.last_failure_time >= self.recovery_timeout:
self.state = CircuitState.HALF_OPEN
self.success_count = 0
logger.info("회로 차단기: HALF_OPEN 상태 전환")
else:
raise CircuitOpenException(
f"회로 차단기 OPEN: {self.recovery_timeout}초 후 재시도"
)
try:
result = func(*args, **kwargs)
self._on_success()
return result
except Exception as e:
self._on_failure()
raise
def _on_success(self):
self.failure_count = 0