Ë
    ç©Àjt!  ã                  ó>  — d dl mZ d dlZd dlZd dlZd dlZd dlmZ d dlm	Z	m
Z
 d dlmZ d dlmZmZmZmZmZmZ  ej(                  d«      ZdZd	Zd
Zdd„Zdd„Zdd„Z	 	 	 	 	 	 dd„Zdd„Z G d„ d«      Zeeeeedœ	 	 	 	 	 	 	 	 	 	 	 dd„Zdd„Z e!dk(  r e «        yy)é    )ÚannotationsN)Ú	timedelta)Úcreate_engineÚtext)Údatabase_url)ÚDEFAULT_BATCH_SIZEÚ!DEFAULT_RECONCILE_OVERLAP_MINUTESÚDEFAULT_RECONCILE_WINDOW_HOURSÚbf4sw_database_urlÚrun_catch_upÚrun_reconciliationzbf4ps.discovery_serviceé<   i,  l   SIˆ&AQ1 c                ór   — t        | j                  t        d«      dt        i«      j	                  «       «      S )Nz&SELECT pg_try_advisory_lock(:lock_key)Úlock_key)ÚboolÚexecuter   ÚADVISORY_LOCK_KEYÚ
scalar_one©Ú
connections    úbf4ps/discovery_service.pyÚacquire_service_lockr      s8   € ÜØ×ÑÜÐ9Ó:ØÔ*Ð+ó	
÷ ‰*‹,ó	ð ó    c                óF   — | j                  t        d«      dt        i«       y )Nz$SELECT pg_advisory_unlock(:lock_key)r   )r   r   r   r   s    r   Úrelease_service_lockr   $   s"   € Ø×ÑÜÐ3Ó4Ø	Ô&Ð'õr   c               ó    — t        | ||¬«       y )N©Ú
batch_size)r   )Úsource_engineÚdestination_enginer   s      r   Úrun_discovery_cycler!   +   s   € Ü�Ð 2¸zÖJr   c               ó*  — | j                  «       5 }|j                  «       5 }t        ||||¬«      \  }}}}	d d d «       d d d «       t        j	                  dj                  «       j                  «       	«       y # 1 sw Y   ŒGxY w# 1 sw Y   ŒKxY w)N©Úinitial_window_hoursÚoverlap_minuteszNBF4SW reconciliation complete: since=%s through=%s alias_rows=%d identities=%d)ÚconnectÚbeginr   ÚLOGGERÚinfoÚ	isoformat)
r   r    r$   r%   ÚsourceÚdestinationÚsinceÚthroughÚ
alias_rowsÚ
identitiess
             r   Úrun_reconciliation_cycler1   /   s–   € ð 
×	Ñ	Ó	 ð  FØ×%Ñ%Ó'ð 	¨;Ü5GØØØ%9Ø /ô	6Ñ2ˆE�7˜J¨
÷	÷ô ‡K�KØXØ�‰ÓØ×ÑÓØØõ÷	ð 	ú÷ð ús!   ‘B	¢A=·B	Á=B	ÂB	Â	Bc                ó4   — t        dt        ||«      | z
  «      S )Ng        )ÚmaxÚmin)ÚnowÚdiscovery_dueÚreconcile_dues      r   Úseconds_until_duer8   G   s   € Üˆs”C˜ }Ó5¸Ñ;Ó<Ð<r   c                  ó(   — e Zd ZdZdd„Zdd„Zdd„Zy)	ÚCycleFailureLoggerzSLog the first consecutive failure with traceback, then stay concise until recovery.c                ó    — || _         d| _        y )Nr   )Ú	operationÚconsecutive_failures)Úselfr<   s     r   Ú__init__zCycleFailureLogger.__init__N   s   € Ø"ˆŒØ$%ˆÕ!r   c                ó  — | xj                   dz  c_         | j                   dk(  r!t        j                  d| j                  «       y t        j	                  d| j                  | j                   t        |«      j                  |«       y )Né   zBF4SW %s cycle failedzBBF4SW %s cycle still failing: consecutive_failures=%d error=%s: %s)r=   r(   Ú	exceptionr<   ÚerrorÚtypeÚ__name__)r>   Úexcs     r   ÚfailedzCycleFailureLogger.failedR   se   € Ø×!Ò! QÑ&Õ!Ø×$Ñ$¨Ò)Ü×ÑÐ4°d·n±nÕEä�L‰LØTØ—‘Ø×)Ñ)Ü�S“	×"Ñ"Øõr   c                ó‚   — | j                   r3t        j                  d| j                  | j                   «       d| _         y y )Nz8BF4SW %s cycle recovered after %d consecutive failure(s)r   )r=   r(   r)   r<   )r>   s    r   Ú	succeededzCycleFailureLogger.succeeded_   s9   € Ø×$Ò$Ü�K‰KØJØ—‘Ø×)Ñ)ôð
 )*ˆDÕ%ð %r   N)r<   Ústr)rF   Ú	ExceptionÚreturnÚNone©rL   rM   )rE   Ú
__module__Ú__qualname__Ú__doc__r?   rG   rI   © r   r   r:   r:   K   s   „ Ù]ó&óô*r   r:   ©r   Údiscovery_interval_secondsÚreconcile_interval_secondsr$   r%   c          
     óh  ‡— |dk  rt        d«      ‚|dk  rt        d«      ‚dŠt        d«      }t        d«      }ˆfd„}	i }
t        j                  t        j                  fD ]  }t        j                  ||	«      |
|<   Œ |j                  «       }	 t        |«      smt        j                  d«       	 	 |j                  st        |«       |j                  «        |
j                  «       D ]  \  }}t        j                  ||«       Œ y
t        j                  d«       	 t!        | ||¬«       |j#                  «        	 t'        | |||¬«       |j#                  «        t)        j*                  «       }||z   }||z   }‰sát)        j*                  «       }||k\  r6	 t!        | ||¬«       |j#                  «        t)        j*                  «       |z   }t)        j*                  «       }||k\  r7	 t'        | |||¬«       |j#                  «        t)        j*                  «       |z   }‰rn?t)        j,                  t/        dt1        t)        j*                  «       ||«      «      «       ‰sŒát        j                  d«       	 	 |j                  st        |«       |j                  «        |
j                  «       D ]  \  }}t        j                  ||«       Œ y# t        $ r t        j                  d	«       Y �Œ"w xY w# t        $ r}|j%                  |«       Y d }~�ŒÓd }~ww xY w# t        $ r}|j%                  |«       Y d }~�ŒÛd }~ww xY w# t        $ r}|j%                  |«       Y d }~�Œ«d }~ww xY w# t        $ r}|j%                  |«       Y d }~�Œƒd }~ww xY w# t        $ r t        j                  d	«       Y �Œ%w xY w# 	 |j                  st        |«       n$# t        $ r t        j                  d	«       Y nw xY w|j                  «        |
j                  «       D ]  \  }}t        j                  ||«       Œ w xY w)NrA   z-discovery_interval_seconds must be at least 1z-reconcile_interval_seconds must be at least 1FÚ	discoveryÚreconciliationc                ó6   •— dŠt         j                  d| «       y )NTzShutdown requested by signal %s)r(   r)   )ÚsignumÚframeÚstoppings     €r   Úrequest_stopz!run_service.<locals>.request_stop|   s   ø€ àˆÜ�‰Ð5°vÕ>r   zJAnother BF4PS discovery service already holds the PostgreSQL advisory lockz7Failed to release BF4PS discovery service advisory locké   z%BF4PS discovery service lock acquiredr   r#   g      ð?z BF4PS discovery service stoppingr   )Ú
ValueErrorr:   ÚsignalÚSIGINTÚSIGTERMr&   r   r(   rC   Úclosedr   rK   rB   ÚcloseÚitemsr)   r!   rI   rG   r1   ÚtimeÚ	monotonicÚsleepr4   r8   )r   r    r   rT   rU   r$   r%   Údiscovery_failuresÚreconciliation_failuresr]   Úprevious_handlersÚsigÚlock_connectionÚhandlerrF   r5   r6   r7   r\   s                     @r   Úrun_servicero   i   sã  ø€ ð " AÒ%ÜÐHÓIÐIØ! AÒ%ÜÐHÓIÐIà€HÜ+¨KÓ8ÐÜ0Ð1AÓBÐô?ð
 ÐÜ—‘œvŸ~™~Ð.ò BˆÜ!'§¡¨s°LÓ!AÐ˜#ÒðBð )×0Ñ0Ó2€OðI(Ü# OÔ4Ü�L‰LÐeÔfØð~	XØ"×)Ò)Ü$ _Ô5ð 	×ÑÔØ-×3Ñ3Ó5ò 	(‰LˆC�Ü�M‰M˜#˜wÕ'ñ	(ôG 	�‰Ð;Ô<ð
	+Ü Ð/AÈjÕYð ×(Ñ(Ô*ð
	0Ü$ØØ"Ø%9Ø /õ	ð $×-Ñ-Ô/ä�n‰nÓˆØÐ8Ñ8ˆØÐ8Ñ8ˆáÜ—.‘.Ó"ˆCØ�mÒ#ð3Ü'¨Ð7IÐV`Õað '×0Ñ0Ô2Ü $§¡Ó 0Ð3MÑ M�ä—.‘.Ó"ˆCØ�mÒ#ð
8Ü,Ø%Ø*Ø-AØ(7õ	ð ,×5Ñ5Ô7Ü $§¡Ó 0Ð3MÑ M�áØÜ�J‰J”s˜3Ô 1´$·.±.Ó2BÀMÐS`Ó aÓbÔcò9 ô< 	�‰Ð6Ô7Øð	XØ"×)Ò)Ü$ _Ô5ð 	×ÑÔØ-×3Ñ3Ó5ò 	(‰LˆC�Ü�M‰M˜#˜wÕ'ñ	(øô ò 	XÜ×ÑÐV×Wð	Xûôs ò 	+Ø×%Ñ% c×*Ò*ûð	+ûô ò 	0Ø#×*Ñ*¨3×/Ò/ûð	0ûô !ò 3Ø&×-Ñ-¨c×2Ò2ûð3ûô !ò 8Ø+×2Ñ2°3×7Ò7ûð8ûô  ò 	XÜ×ÑÐV×Wð	Xûð	XØ"×)Ò)Ü$ _Ô5ùÜò 	XÜ×ÑÐVÖWð	Xúà×ÑÔØ-×3Ñ3Ó5ò 	(‰LˆC�Ü�M‰M˜#˜wÕ'ñ	(ús  Â N4 Â2K
 ÄN4 ÄK/ Ä,N4 Ä=L ÅA	N4 ÆL? Æ$A N4 Ç%M' Ç4A(N4 ÉN4 É4N Ë
K,Ë+K,Ë/	LË8LÌ	N4 ÌLÌN4 Ì	L<Ì L7Ì1N4 Ì7L<Ì<N4 Ì?	M$ÍMÍN4 ÍM$Í$N4 Í'	NÍ0NÎN4 ÎNÎN4 ÎN1Î0N1Î4P1Î6OÏP1ÏO/Ï,P1Ï.O/Ï/AP1c                 óÒ  — t        j                  d¬«      } | j                  dt        t        ¬«       | j                  dt        t
        ¬«       | j                  dt        t        ¬«       | j                  dt        t        ¬«       | j                  dt        t        ¬«       | j                  d	d
d¬«       | j                  «       }t        j                  t        t        |j                  «      d¬«       t        t        «       «      }t        t!        «       «      }t#        t%        |||j&                  |j(                  |j*                  |j,                  |j.                  ¬«      «      ‚)Nz>Continuously discover and reconcile BF4SW soldiers into BF4PS.)Údescriptionz--batch-size)rD   Údefaultz--discovery-interval-secondsz--reconcile-interval-secondsz--reconcile-window-hoursz--reconcile-overlap-minutesz--log-levelÚINFO)ÚDEBUGrs   ÚWARNINGÚERROR)rr   Úchoicesz.%(asctime)s %(levelname)s %(name)s %(message)s)ÚlevelÚformatrS   )ÚargparseÚArgumentParserÚadd_argumentÚintr   Ú"DEFAULT_DISCOVERY_INTERVAL_SECONDSÚ"DEFAULT_RECONCILE_INTERVAL_SECONDSr
   r	   Ú
parse_argsÚloggingÚbasicConfigÚgetattrÚ	log_levelr   r   r   Ú
SystemExitro   r   rT   rU   Úreconcile_window_hoursÚreconcile_overlap_minutes)ÚparserÚargsr   r    s       r   ÚmainrŠ   Ò   s+  € Ü×$Ñ$Ð1qÔr€FØ
×Ñ˜¬SÔ:LÐÔMØ
×ÑÐ6¼SÔJlÐÔmØ
×ÑÐ6¼SÔJlÐÔmØ
×ÑÐ2¼ÔFdÐÔeØ
×ÑÐ5¼CÔIjÐÔkØ
×Ñ˜¨vÐ?dÐÔeØ×ÑÓ€Dä×ÑÜ”g˜tŸ~™~Ó.Ø?õô
 "Ô"4Ó"6Ó7€MÜ&¤|£~Ó6ÐÜ
ÜØØØ—‘Ø'+×'FÑ'FØ'+×'FÑ'FØ!%×!<Ñ!<Ø ×:Ñ:ô	
ó
ð 
r   Ú__main__)rL   r   rN   )r   r}   rL   rM   )r$   r}   r%   r}   rL   rM   )r5   Úfloatr6   rŒ   r7   rŒ   rL   rŒ   )r   r}   rT   r}   rU   r}   r$   r}   r%   r}   rL   r}   )"Ú
__future__r   rz   r�   r`   rf   Údatetimer   Ú
sqlalchemyr   r   Úbf4ps.configr   Úbf4ps.discoveryr   r	   r
   r   r   r   Ú	getLoggerr(   r~   r   r   r   r   r!   r1   r8   r:   ro   rŠ   rE   rR   r   r   ú<module>r“      s  ðÝ "ã Û Û Û Ý ç *å %÷÷ ð 
ˆ×	Ñ	Ð4Ó	5€Ø%'Ð "Ø%(Ð "Ø&Ð óóóKðð ð	ð
 ðð 
óó0=÷*ñ *ðD )Ø&HØ&HØ >Ø<ñf(ð ð	f(ð
 !$ðf(ð !$ðf(ð ðf(ð ðf(ð 	óf(óRð< ˆzÒÙ…Fð r   