
    i_M                        d Z ddlZddlZddlZddlZddlmZmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZ  ee      Z eej&                  j)                  d	d
            Zedz  dz  dz  Zedz  dz  ZdZ G d de
      Z G d de
      Z G d de      Z G d de      Z G d de      Z	 	 d3dededede e   dz  dedz  ded dfd!Z! G d" d#      Z" G d$ d%      Z# G d& d'      Z$	 	 d4ded(ed)ed*ed e$f
d+Z%d,ejL                  d dfd-Z'd,ejL                  d dfd.Z(d,ejL                  d dfd/Z)d,ejL                  d dfd0Z*d5d1Z+ed2k(  r e+        yy)6u9  
Circuit Breaker 모듈 — 에러 임계치 기반 자동 차단 + 복구 전략.

Usage:
    from utils.circuit_breaker import create_circuit_breaker
    cb = create_circuit_breaker("pyright_check", strategy_type="autofix")
    action = cb.record_error({"message": "...", "source": "pyright", "details": None})
    N)ABCabstractmethod)datetime)Enum)Path)Any)
get_loggerWORKSPACE_ROOTz/home/jay/workspacememorylogszcircuit-breakerescalations2   c                       e Zd ZdZdZdZdZy)RecoveryActionretryrollbackescalateskipN)__name__
__module____qualname__RETRYROLLBACKESCALATESKIP     F/home/jay/workspace/.worktrees/task-2116-dev1/utils/circuit_breaker.pyr   r   $   s    EHHDr   r   c                       e Zd ZdZdZdZy)CircuitStateclosedopen	half_openN)r   r   r   CLOSEDOPEN	HALF_OPENr   r   r   r    r    +   s    FDIr   r    c            	       L    e Zd Zededededefd       Zedededdfd       Z	y)	RecoveryStrategycontext
error_infoattemptreturnc                      y)uc   에러 발생 시 복구 액션 결정. error_info: {"message": str, "source": str, "details": any}Nr   selfr)   r*   r+   s       r   on_errorzRecoveryStrategy.on_error7       r   error_countNc                      y)u-   서킷이 OPEN 상태로 전환될 때 호출Nr   r/   r)   r2   s      r   on_circuit_openz RecoveryStrategy.on_circuit_open;   r1   r   )
r   r   r   r   strdictintr   r0   r5   r   r   r   r(   r(   6   s_    r r r r r r <s < < < <r   r(   c                   N    e Zd ZdZddeddfdZdedededefd	Z	ded
eddfdZ
y)AutoFixStrategyuC   fireauto 패턴: threshold 미만이면 RETRY, 초과 시 ESCALATE.	thresholdr,   Nc                     || _         y Nr;   )r/   r;   s     r   __init__zAutoFixStrategy.__init__H   s	    "r   r)   r*   r+   c                 `    || j                   k  rt        j                  S t        j                  S r=   )r;   r   r   r   r.   s       r   r0   zAutoFixStrategy.on_errorK   s&    T^^#!'''&&&r   r2   c                 x    t         j                  d| d|        t        |d| d| j                   d|       y )Nu&   [CircuitBreaker] OPEN 전환: context=, error_count=   에러 u   회 연속 — threshold(u   ) 초과r)   reasonr2   )loggerwarning_write_escalation_filer;   r4   s      r   r5   zAutoFixStrategy.on_circuit_openP   sE    ?yWbVcde[M)B4>>BRRZ[#	
r   )   )r   r   r   __doc__r8   r?   r6   r7   r   r0   r5   r   r   r   r:   r:   E   sS    M## #d #' ' ' ' '

s 
 
 
r   r:   c                   <    e Zd ZdZdedededefdZdededdfd	Z	y)
EscalationStrategyu.   gstack 패턴: 즉시 ESCALATE (CRITICAL GAP).r)   r*   r+   r,   c                 "    t         j                  S r=   )r   r   r.   s       r   r0   zEscalationStrategy.on_errora   s    &&&r   r2   Nc                 (    t        |d| d|       y )NrC   u.   회 연속 — escalation 전략 즉시 발동rD   )rH   r4   s      r   r5   z"EscalationStrategy.on_circuit_opend   s    [M)WX#	
r   )
r   r   r   rJ   r6   r7   r8   r   r0   r5   r   r   r   rL   rL   ^   s@    8' ' ' ' '
s 
 
 
r   rL   r)   rE   r2   last_errorsoutput_pathextrar,   c                 `   	 | |}|j                   j                  dd       nIt        j                  dd       t        j                         j                  d      }t        |  d| dz  }| t        j                         j                         ||d|xs g d}|r|j                  |       t        |dd	
      5 }	t        j                  ||	dd       d d d        t        j                  d|        y # 1 sw Y   "xY w# t        $ r"}
t        j                  d|
        Y d }
~
y d }
~
ww xY w)NTparentsexist_ok%Y%m%dT%H%M%S_z_escalation.json
escalation)r)   triggered_atrE   r2   actionrO   wutf-8encodingF   ensure_asciiindentu+   [CircuitBreaker] escalation 파일 생성: u2   [CircuitBreaker] escalation 파일 생성 실패: )parentmkdirESCALATIONS_DIRr   nowstrftime	isoformatupdater"   jsondumprF   rG   OSErrorerror)r)   rE   r2   rO   rP   rQ   filepathtspayloadfes              r   rH   rH   q   s    O""HOO!!$!>!!$!>((9B&G9AbT9I)JJH$LLN446&"&,"
 NN5!(C'2 	@aIIgquQ?	@DXJOP	@ 	@  OI!MNNOs0   B9D ;C6 D 6C?;D 	D-D((D-c                   |    e Zd ZdZddZdeddfdZdee   ddfdZdee   fd	Z	dede
fd
Zedee   fd       Zy)FileSnapshotu!   파일 내용 스냅샷 + 복원.r,   Nc                     i | _         y r=   )
_snapshotsr/   s    r   r?   zFileSnapshot.__init__   s	    13r   rn   c                     	 t        |      }|j                         r |j                  d      | j                  |<   yd| j                  |<   y# t        $ r%}t
        j                  d| d|        Y d}~yd}~ww xY w)uC   파일 현재 내용을 스냅샷. 파일이 없으면 None 저장.r\   r]   Nu   [FileSnapshot] capture 실패: , )r   exists	read_textrv   rl   rF   rm   )r/   rn   prr   s       r   capturezFileSnapshot.capture   sp    	LXAxxz,-KKK,I),0) 	LLL:8*BqcJKK	Ls   :A A 	A;A66A;	filepathsc                 4    |D ]  }| j                  |        y)u   여러 파일 스냅샷N)r}   )r/   r~   fps      r   capture_multiplezFileSnapshot.capture_multiple   s     	BLL	r   c                     g }t        | j                  j                               D ]%  }| j                  |      s|j	                  |       ' |S )u`   모든 스냅샷 파일을 원래 내용으로 복원. 복원된 파일 경로 리스트 반환.)listrv   keysrestore_fileappend)r/   restoredr   s      r   restorezFileSnapshot.restore   sI    t++-. 	$B  $#	$ r   c                 `   || j                   vry	 t        |      }| j                   |   }|!|j                         r|j                          y|j                  j                  dd       |j                  |d       y# t        $ r%}t        j                  d| d|        Y d}~yd}~ww xY w)	u   단일 파일 복원FNTrS   r\   r]   u$   [FileSnapshot] restore_file 실패: ry   )
rv   r   rz   unlinkrc   rd   
write_textrl   rF   rm   )r/   rn   r|   contentrr   s        r   r   zFileSnapshot.restore_file   s    4??*	XAooh/G88:HHJ  td;Ww7 	LL?zA3OP	s   <A? 0A? ?	B-B((B-c                 H    t        | j                  j                               S )u   스냅샷된 파일 목록)r   rv   r   rw   s    r   fileszFileSnapshot.files   s     DOO((*++r   r,   N)r   r   r   rJ   r?   r6   r}   r   r   r   boolr   propertyr   r   r   r   rt   rt      sy    +4	L 	L 	L$s)  
c S T $ ,tCy , ,r   rt   c                   l    e Zd ZdZddededdfdZdee   defdZd	eddfd
Z	d	ede
fdZd	ede
fdZy)RollbackManageru"   스냅샷 기반 롤백 관리자.task_idscoper,   Nc                      || _         || _        y r=   )r   r   )r/   r   r   s      r   r?   zRollbackManager.__init__   s    
r   r~   c                 ^    t               }|j                  |       | j                  |       |S )u    스냅샷 생성 + 영속 저장)rt   r   _persist_snapshot)r/   r~   snapshots      r   create_snapshotzRollbackManager.create_snapshot   s*    >!!),x(r   r   c           
         	 t         dz  dz  dz  }|j                  dd       t        j                         j	                  d      }|| j
                   d| j                   d| dz  }| j
                  | j                  t        j                         j                         |j                  |j                  D ci c]  }||j                  |    c}d	}t        |d
d      5 }t        j                  ||dd       d d d        y c c}w # 1 sw Y   y xY w# t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nr   r   zrollback-snapshotsTrS   rV   rW   .json)r   r   
created_atr   contentsr[   r\   r]   Fr_   r`   u2   [RollbackManager] 스냅샷 영속 저장 실패: )	WORKSPACErd   r   rf   rg   r   r   rh   r   rv   r"   rj   rk   rl   rF   rm   )	r/   r   snap_dirro   	snap_filer   datarq   rr   s	            r   r   z!RollbackManager._persist_snapshot   s'   	S 8+f47KKHNN4$N7((9B dll^1TZZL"U#KKI<<&lln668!CK>>RRR!4!4R!88RD iw7 A1		$a@A A SA A 	SLLMaSQRR	SsH   B7D 9DD #D=D D DD D 	E D==Ec                    g }g }|j                   D ]6  }|j                  |      r|j                  |       &|j                  |       8 t        |      dk(  }t        j                  dt        |       dt        |              |||dS )u   롤백 수행.r   u,   [RollbackManager] rollback 완료: restored=z	, failed=)successr   failed)r   r   r   lenrF   info)r/   r   r   r   r   r   s         r   r   zRollbackManager.rollback   s     .. 	"B$$R(#b!		"
 f+"B3x=/QZ[^_e[fZghi"FKKr   c                     | j                  |      }|d   s*t        | j                  d|d    t        |d                |S )u6   롤백 시도 → 실패 시 escalation 파일 생성.r   u(   롤백 실패 — 수동 개입 필요: r   rD   )r   rH   r   r   )r/   r   results      r   rollback_with_escalationz(RollbackManager.rollback_with_escalation   sK    x(i "A&BRASTx 01
 r   )last_operation)r   r   r   rJ   r6   r?   r   rt   r   r   r7   r   r   r   r   r   r   r      su    , C t c | S, S4 S$L L$ L	 	$ 	r   r   c                       e Zd ZdZ	 	 	 ddedededededdfd	Ze	de
fd
       Ze	defd       ZdedefdZddZdefdZddZdeddfdZdefdZddZddZy)CircuitBreakeru,   에러 임계치 기반 서킷 브레이커.r)   strategyr;   cooldown_seconds
persistentr,   Nc                     || _         || _        || _        || _        || _        t
        j                  | _        d| _        d | _	        d | _
        g | _        g | _        | j                  r| j                          y y )Nr   )r)   r   r;   r   r   r    r$   _state_error_count_last_error_ts_last_success_ts_history_last_errors_load_state)r/   r)   r   r;   r   r   s         r   r?   zCircuitBreaker.__init__  st      " 0$$0$7$7!"*.,0$&')?? r   c                     | j                   S r=   )r   rw   s    r   statezCircuitBreaker.state+  s    {{r   c                     | j                   S r=   )r   rw   s    r   r2   zCircuitBreaker.error_count/  s       r   r*   c                    |j                  dd      }| j                  j                  |       t        | j                        | j                  kD  r| j                  | j                   d | _        t        j                         j                         }|| _        | j                  t        j                  k(  rA| j                  |d|d       | j                  r| j                          t        j                   S | j                  t        j"                  k(  rxt        j                  | _	        | j                  |d|d       t$        j'                  d| j(                          | j                  r| j                          t        j                   S | xj*                  dz  c_        | j,                  j/                  | j(                  || j*                        }| j                  |d	|d       | j*                  | j                  k\  rt        j                  | _	        | j                  |d
| j*                  d       t$        j'                  d| j(                   d| j*                          	 | j,                  j1                  | j(                  | j*                         | j                  r| j                          |S # t2        $ r"}t$        j5                  d|        Y d}~Dd}~ww xY w)u%   에러 기록 + 복구 액션 결정.message Nblocked)ro   rZ   r   half_open_failu-   [CircuitBreaker] HALF_OPEN → OPEN: context=   rm   circuit_open)ro   rZ   r2   u*   [CircuitBreaker] CLOSED → OPEN: context=rB   u)   [CircuitBreaker] on_circuit_open 오류: )getr   r   r   r;   r   rf   rh   r   r   r    r%   _append_historyr   _save_stater   r   r&   rF   rG   r)   r   r   r0   r5   	Exceptionrm   )r/   r*   msgrf   rZ   rr   s         r   record_errorzCircuitBreaker.record_error3  s?   nnY+  %t  !DNN2 $ 1 14>>/2C DDlln&&(!;;,+++  yS!QR  "!***;;,000&++DK  7GTW!XYNNJ4<<.YZ  "!*** 	Q''j$BSBSTC7sKL.&++DK  ~VZVgVg!hiNN<T\\NJ\]a]n]n\opN--dllD<M<MN ??  NHLMMNs   #0J1 1	K:KKc                    t        j                         j                         }|| _        | j	                  |dd       | j
                  t        j                  k(  rFt        j                  | _        d| _	        g | _
        t        j                  d| j                          n+| j
                  t        j                  k(  rd| _	        g | _
        | j                  r| j                          yy)u   성공 기록.r   ro   rZ   r   u/   [CircuitBreaker] HALF_OPEN → CLOSED: context=N)r   rf   rh   r   r   r   r    r&   r$   r   r   rF   r   r)   r   r   r/   rf   s     r   record_successzCircuitBreaker.record_success_  s    lln&&( #C9=>;;,000&--DK !D "DKKI$,,XY[[L/// !D "D?? r   c                 ~   | j                   t        j                  k7  ry| j                  y	 t	        j
                  | j                        }t	        j                         |z
  j                         }|| j                  k\  rt        j                  | _         t	        j                         j                         }| j                  |dd       t        j                  d| j                   d|dd       | j                  r| j!                          y		 y# t"        $ r"}t        j%                  d
|        Y d}~yd}~ww xY w)u'   cooldown 경과 시 OPEN → HALF_OPEN.FNhalf_open_tryr   u-   [CircuitBreaker] OPEN → HALF_OPEN: context=z
, elapsed=z.0fsTu:   [CircuitBreaker] try_reset 타임스탬프 파싱 오류: )r   r    r%   r   r   fromisoformatrf   total_secondsr   r&   rh   r   rF   r   r)   r   r   
ValueErrorrm   )r/   last_tselapsedrf   rr   s        r   	try_resetzCircuitBreaker.try_resetq  s   ;;,+++&	[,,T-@-@AG||~/>>@G$///*44lln..0$$C?%KLKDLL>Yghopsgttuvw??$$& 0   	[LLUVWUXYZZ	[s   C!D 	D<D77D<c                 4   t         j                  | _        d| _        g | _        t        j                         j                         }| j                  |dd       t        j                  d| j                          | j                  r| j                          yy)u   강제 리셋 → CLOSEDr   force_resetr   u(   [CircuitBreaker] 강제 리셋: context=N)r    r$   r   r   r   r   rf   rh   r   rF   r   r)   r   r   r   s     r   r   zCircuitBreaker.force_reset  sv    "))lln&&(C=AB>t||nMN?? r   entryc                     | j                   j                  |       t        | j                         t        kD  r| j                   t         d  | _         y y r=   )r   r   r   HISTORY_LIMIT)r/   r   s     r   r   zCircuitBreaker._append_history  s>    U#t}}- MM=./:DM .r   c                 .    t         | j                   dz  S )Nr   )CB_STATE_DIRr)   rw   s    r   _state_filepathzCircuitBreaker._state_filepath  s    e444r   c                 6   | j                         }|j                         sy	 t        |d      5 }t        j                  |      }ddd       t        j                  dd            | _        |j                  dd      | _        |j                  d      | _	        |j                  d	      | _
        |j                  d
g       | _        y# 1 sw Y   xY w# t        t        j                  t        f$ r%}t        j!                  d| d|        Y d}~yd}~ww xY w)u$   영속 저장소에서 상태 로드Nr\   r]   r   r!   r2   r   last_error_tslast_success_tshistoryu'   [CircuitBreaker] 상태 로드 실패: ry   )r   rz   r"   rj   loadr    r   r   r   r   r   r   rl   JSONDecodeErrorr   rF   rm   )r/   r   rq   r   rr   s        r   r   zCircuitBreaker._load_state  s    !!#yy{		Nb7+ $qyy|$&txx'BCDK $ :D"&((?";D$(HH->$?D! HHY3DM$ $ --z: 	NLLB2$bLMM	Ns/   C C	BC 	CC D3DDc                    	 t         j                  dd       | j                         }| j                  | j                  j
                  | j                  | j                  | j                  | j                  | j                  d}t        |dd      5 }t        j                  ||dd	       d
d
d
       y
# 1 sw Y   y
xY w# t        $ r"}t        j!                  d|        Y d
}~y
d
}~ww xY w)u!   영속 저장소에 상태 저장TrS   )r)   r   r2   r;   r   r   r   r[   r\   r]   Fr_   r`   Nu'   [CircuitBreaker] 상태 저장 실패: )r   rd   r   r)   r   valuer   r;   r   r   r   r"   rj   rk   rl   rF   rm   )r/   r   r   rq   rr   s        r   r   zCircuitBreaker._save_state  s    	Htd;%%'B<<**#00!^^!%!4!4#'#8#8==D b#0 AA		$a@A A A 	HLLB1#FGG	Hs6   BC  B4+C  4B=9C  =C   	C+	C&&C+)rI   i,  Tr   )r   r   r   rJ   r6   r(   r8   r   r?   r   r    r   r2   r7   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r     s    6  # # 	
   
0 |   !S ! !*t * *X$4 *	;T ;d ;
5 5N Hr   r   strategy_typer;   kwargsc                 X    |dk(  rt               }nt        |      }t        d| ||d|S )u   편의 팩토리 함수rX   r>   )r)   r   r;   r   )rL   r:   r   )r)   r   r;   r   r   s        r   create_circuit_breakerr     sC     $%7%9"Y7  	 r   argsc                 N   t        | j                  | j                        }| j                  | j                  d d}|j	                  |      }| j                  |j
                  j                  |j                  |j                  d}t        t        j                  |d             y )N)r   )r   sourcedetails)r)   r   r2   rZ   Fra   )r   r)   r   r   r   r   r   r2   printrj   dumps)r   cbr*   rZ   r   s        r   _cli_record_errorr     st    	DMM	JB!\\T\\dSJ__Z(F<<~~,,	F 
$**V%
01r   c                     t        | j                        }| j                  |j                  j                  |j                  d}t        t        j                  |d             y N)r)   r   r2   Fr   )r   r)   r   r   r2   r   rj   r   r   r   r   s      r   
_cli_checkr     sE    		-B<<~~F
 
$**V%
01r   c                     t        | j                        }|j                          | j                  |j                  j                  |j
                  d}t        t        j                  |d             y r   )	r   r)   r   r   r   r2   r   rj   r   r   s      r   _cli_record_successr     sQ    		-B<<~~F
 
$**V%
01r   c                     t        | j                        }|j                          | j                  |j                  j                  |j
                  d}t        t        j                  |d             y r   )	r   r)   r   r   r   r2   r   rj   r   r   s      r   
_cli_resetr     sO    		-BNN<<~~F
 
$**V%
01r   c                  `   t        j                  dd      } | j                  dd      }|j                  dd	      }|j	                  d
dd       |j	                  ddd       |j	                  ddddgd       |j                  t               |j                  dd	      }|j	                  d
dd       |j                  t               |j                  dd	      }|j	                  d
dd       |j                  t               |j                  dd	      }|j	                  d
dd       |j                  t               | j                         }	 |j                  |       y # t        $ r7}t        j                  d|        t        j                   d       Y d }~y d }~ww xY w)Ncircuit_breakerzCircuit Breaker CLI)progdescriptioncommandT)destrequiredzrecord-erroru   에러 기록)helpz	--contextu   컨텍스트 키)r  r  z	--messageu   에러 메시지z
--strategyautofixrX   u   복구 전략)defaultchoicesr  )funcchecku   상태 확인zrecord-successu   성공 기록resetu   강제 리셋u   [CircuitBreaker CLI] 오류: r   )argparseArgumentParseradd_subparsers
add_parseradd_argumentset_defaultsr   r   r   r   
parse_argsr  r   rF   rm   sysexit)parser
subparsersp_errp_checkp_okp_resetr   rr   s           r   mainr    s   $$)F &&I&EJ !!.!GE	{T8JK	{T8JK	L)	   
-. ##G/#BGt:LMj)   !1 HDkD7IJ./ ##G/#BGt:LMj)D		$ 4QC89s   E- -	F-6-F((F-__main__)NN)r  rI   r   ),rJ   r	  rj   osr  abcr   r   r   enumr   pathlibr   typingr   utils.loggerr	   r   rF   environr   r   r   re   r   r   r    r(   r:   rL   r6   r8   r   rH   rt   r   r   r   	Namespacer   r   r   r   r  r   r   r   <module>r"     s     	 
 #     #	H	 02GHI	8#f,/@@h&6T 4 <s <
& 
2
) 
. %)#OOO O cT!	O
 O O 
OL3, 3,v6 6|jH jHh #  	
 2
2H.. 
24 
22X'' 2D 22h00 2T 22X'' 2D 2'T zF r   