Ë
    Ö’Tij<  ã                   ó  — d 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
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 ddlmZ ddlmZmZ ddlmZ ddlmZm Z   ejB                  e"«      Z# G d„ d«      Z$ G d„ de«      Z%y)z
Base class for cron tasks.
é    N)ÚABCÚabstractmethod)Údate)ÚOptionalÚDictÚAny)Útransaction)Úsettings)Útimezone)ÚCronExecution)ÚExecutionPattern)ÚDatabaseLock)ÚValidationErrorÚConcurrentExecutionError)ÚNotificationManager)ÚCronjobHookContextÚget_global_cronjob_hook_managerc                   óL   — e Zd ZdZddedededededee   d	eeee	f      fd
„Z
y)ÚExecutionResultzResult of task execution.NÚsuccessÚmessageÚ
error_codeÚskippedÚreasonÚ	exceptionÚdatac                 ón   — || _         || _        || _        || _        || _        || _        |xs i | _        y )N)r   r   r   r   r   r   r   )Úselfr   r   r   r   r   r   r   s           úM/home/cursorai/projects/django-cronjob-utils/src/django_cronjob_utils/base.pyÚ__init__zExecutionResult.__init__   s7   € ØˆŒØˆŒØ$ˆŒØˆŒØˆŒØ"ˆŒØ’J˜Bˆ�	ó    )TÚ r"   Fr"   NN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚboolÚstrr   Ú	Exceptionr   r   r    © r!   r   r   r      s   „ Ù#ñ ð °cð ÈCð Ð_cð Ðuxð ð  KSð  T]ñ  K^ð ð  muð  vzð  {~ð  @Cð  {Cñ  vDñ  mEô r!   r   c                   óz  — e Zd ZU dZdZeed<   dZeed<   ej                  Z
eed<   dZeed<   dZeed	<   d
Zeed<   dZee   ed<   defd„Zd„ Zdefd„Zd„ Zdefd„Zdefd„Zdefd„Zdefd„Zdedefd„Zdefd„Zd„ Z defd„Z!d'dee   dee"ee#f      de$fd „Z%d!e$fd"„Z&d!e$fd#„Z'defd$„Z(e)d%ede*fd&„«       Z+y)(ÚCronTaskz'Abstract base class for all cron tasks.r"   Ú	task_nameÚ	task_codeÚexecution_patternFÚretry_on_failurer   Úmax_retriesi,  Úretry_delayNÚtimeoutÚexecution_datec                 ó˜   — || _         || _        d| _        t        «       | _        t        «       | _        |j                  dd«      | _        y)zÄ
        Initialize cron task.
        
        Args:
            execution_date: Date for which the task should be executed
            **options: Additional options (e.g., force, rerun)
        NÚenable_hooksT)	r4   ÚoptionsÚ	executionr   Ú_notification_managerr   Ú_hook_managerÚgetÚ_enable_hooks)r   r4   r7   s      r   r    zCronTask.__init__0   sC   € ð -ˆÔØˆŒØ26ˆŒÜ%8Ó%:ˆÔ"Ü<Ó>ˆÔØ$Ÿ[™[¨¸Ó>ˆÕr!   c                 óz   — t        | j                  t        «      s!t        dt	        | j                  «      › �«      ‚y)zBValidate task input. Override in subclasses for custom validation.z*execution_date must be a date object, got N)Ú
isinstancer4   r   r   Útype©r   s    r   ÚvalidatezCronTask.validate?   s7   € ä˜$×-Ñ-¬tÔ4Ü!Ð$NÌtÐTX×TgÑTgÓOhÐNiÐ"jÓkÐkð 5r!   Úreturnc                 óD  — | j                   j                  dd«      }|ry| j                   j                  dd«      }|ry| j                  t        j                  k(  ry| j                  t        j
                  k(  rEt        j                  j                  | j                  | j                  d¬«      j                  «        S | j                  t        j                  k(  ryt        j                  j                  | j                  | j                  d¬«      j                  «        S )z0Check if task should run (duplicate prevention).ÚforceFTÚrerun)r.   r4   r   )r.   r4   Ú	completed)r7   r;   r/   r   ÚALWAYSÚRERUN_ON_FAILUREr   ÚobjectsÚfilterr.   r4   ÚexistsÚRATE_LIMITED)r   rD   rE   s      r   Ú
should_runzCronTask.should_runD   s  € à—‘× Ñ  ¨%Ó0ˆÙØà—‘× Ñ  ¨%Ó0ˆÙØà×!Ñ!Ô%5×%<Ñ%<Ò<Øà×!Ñ!Ô%5×%FÑ%FÒFä$×,Ñ,×3Ñ3ØŸ.™.Ø#×2Ñ2Øð 4ó ÷ ‰f‹hð	ð ð ×!Ñ!Ô%5×%BÑ%BÒBàô !×(Ñ(×/Ñ/Ø—n‘nØ×.Ñ.Øð 0ó 
÷ ‰&‹(ð	ð 	r!   c                 óB   — t        | j                  | j                  «      S )z6Acquire database lock to prevent concurrent execution.)r   r.   r4   r@   s    r   Úacquire_lockzCronTask.acquire_locke   s   € ä˜DŸN™N¨D×,?Ñ,?Ó@Ð@r!   c                 óÎ   — t         j                  j                  | j                  | j                  | j
                  t        j                  «       dd¬«      | _        | j                  S )z$Create execution record in database.F)r.   r-   r4   ÚpidrF   r   )	r   rI   Úcreater.   r-   r4   ÚosÚgetpidr8   r@   s    r   Úcreate_execution_recordz CronTask.create_execution_recordi   sQ   € ä&×.Ñ.×5Ñ5Ø—n‘nØ—n‘nØ×.Ñ.Ü—	‘	“ØØð 6ó 
ˆŒð �~‰~Ðr!   c                 óZ   — | j                   r| j                  «       S | j                  «       S )zExecute with optional timeout.)r3   Ú_execute_with_signal_timeoutÚ_executer@   s    r   Úexecute_with_timeoutzCronTask.execute_with_timeoutu   s$   € à�<Š<Ø×4Ñ4Ó6Ð6Ø�}‰}‹Ðr!   c                 ó.  ‡ — t        t        d«      s3t        j                  d‰ j                  › d�«       ‰ j                  «       S ˆ fd„}t        j                  t        j                  |«      }t        j                  ‰ j                  «       	 ‰ j                  «       }t        j                  d«       t        j                  t        j                  |«       |S # t        j                  d«       t        j                  t        j                  |«       w xY w)z.Execute with signal-based timeout (Unix only).ÚSIGALRMz-Timeout not supported on this platform. Task z will run without timeout.c                 ó6   •— t        d‰j                  › d�«      ‚)Nz#Task execution exceeded timeout of ú seconds)ÚTimeoutErrorr3   )ÚsignumÚframer   s     €r   Útimeout_handlerz>CronTask._execute_with_signal_timeout.<locals>.timeout_handler†   s   ø€ ÜÐ!DÀTÇ\Á\ÀNÐRZÐ[Ó\Ð\r!   r   )	ÚhasattrÚsignalÚloggerÚwarningr-   rX   r[   Úalarmr3   )r   ra   Úold_handlerÚresults   `   r   rW   z%CronTask._execute_with_signal_timeout{   sÂ   ø€ ô ”v˜yÔ)Ü�N‰NðØŸ™Ð'Ð'AðCôð —=‘=“?Ð"ô	]ô —m‘m¤F§N¡N°OÓDˆÜ�‰�T—\‘\Ô"ð	7Ø—]‘]“_ˆFô �L‰L˜ŒOÜ�M‰Mœ&Ÿ.™.¨+Ô6àˆøô �L‰L˜ŒOÜ�M‰Mœ&Ÿ.™.¨+Õ6ús   ÂC Ã;Dc                 ó  — 	 | j                  | j                  «      }t        |t        «      r?t	        |j                  dd«       |j                  dd«      |j                  dd«      ¬«      S t        |t        «      r|S t	        d|rt        |«      ¬	«      S d¬	«      S # t        $ rX}| j                  |«      }t        j                  d
| j                  › d|› �«       t	        dt        |«      ||¬«      cY d}~S d}~ww xY w)zInternal execution method.ÚerrorFr   r"   r   ©r   r   r   TzTask completed successfully)r   r   úTask z execution failed: )r   r   r   r   N)Úexecuter4   r>   Údictr   r;   r(   r)   Úget_error_coderd   r   r-   )r   rh   Úer   s       r   rX   zCronTask._execute–   sú   € ð	Ø—\‘\ $×"5Ñ"5Ó6ˆFô ˜&¤$Ô'Ü&Ø &§
¡
¨7°EÓ :Ð:Ø"ŸJ™J y°"Ó5Ø%Ÿz™z¨,¸Ó;ôð ô ˜&¤/Ô2Ø�ô #ØÙ'-œ˜F›ôð à3Pôð øô ò 	Ø×,Ñ,¨QÓ/ˆJÜ×Ñ˜u T§^¡^Ð$4Ð4GÈÀsÐKÔLÜ"ØÜ˜A›Ø%Øô	õ ûð	ús1   ‚A)B Á,B Á>B ÂB Â	C>Â&AC9Ã3C>Ã9C>r   c                 ó.   — |j                   j                  S )z?Get error code from exception. Override for custom error codes.)Ú	__class__r#   )r   r   s     r   ro   zCronTask.get_error_code¶   s   € à×"Ñ"×+Ñ+Ð+r!   c                 ó€   — | j                   sy| j                  sy| j                  j                  | j                  k\  ryy)z Check if task should be retried.FT)r0   r8   Úretry_countr1   r@   s    r   Úshould_retryzCronTask.should_retryº   s6   € à×$Ò$Øà�~Š~Øà�>‰>×%Ñ%¨×)9Ñ)9Ò9Øàr!   c                 óþ   — | j                   r| j                   j                  «        t        j                  d| j                   j                  dz   › d| j
                  › d| j                  › d| j                  › d�	«       y)z:Schedule retry execution. Override for custom retry logic.zScheduling retry é   Ú/z
 for task z after r]   N)r8   Úincrement_retryrd   Úinfort   r1   r-   r2   r@   s    r   Úschedule_retryzCronTask.schedule_retryÇ   sn   € à�>Š>Ø�N‰N×*Ñ*Ô,ä�‰Ø §¡× :Ñ :¸QÑ >Ð?¸qÀ×AQÑAQÐ@Rð SØŸ™Ð' w¨t×/?Ñ/?Ð.@ÀðJõ	
r!   rh   c                 óŠ   — | j                   r7|j                  xs d}| j                  j                  | j                   |«       yy)zNotify stakeholders of failure.zUnknown errorN)r8   r   r9   Únotify_failure)r   rh   Úerror_messages      r   r}   zCronTask.notify_failureÕ   s6   € à�>Š>Ø"ŸN™NÒ=¨oˆMØ×&Ñ&×5Ñ5°d·n±nÀmÕTð r!   Úexecution_idÚmetadatac                 óÚ   — t        d| j                  | j                  | j                  | j                  || j
                  r| j
                  j                  nd| j                  |xs i ¬«	      S )z*Create hook context for current execution.rm   r   )	Ú	operationr.   r-   r4   r/   r   rt   r7   r€   )r   r.   r-   r4   r/   r8   rt   r7   )r   r   r€   s      r   Ú_create_hook_contextzCronTask._create_hook_contextÛ   sX   € ä!ØØ—n‘nØ—n‘nØ×.Ñ.Ø"×4Ñ4Ø%Ø6:·n²n˜Ÿ™×2Ò2È!Ø—L‘LØ’^ ô

ð 
	
r!   Úcontextc                 ór   — | j                   sy	 | j                  j                  |«       y# t        $ r ‚ w xY w)z(Execute PRE hooks before task execution.N)r<   r:   Úexecute_pre_hooksr)   ©r   r„   s     r   Ú_execute_pre_hookszCronTask._execute_pre_hooksé   s9   € à×!Ò!Øð	Ø×Ñ×0Ñ0°Õ9øÜò 	àð	ús   �+ «6c                 óT   — | j                   sg S | j                  j                  |«      S )z(Execute POST hooks after task execution.)r<   r:   Úexecute_post_hooksr‡   s     r   Ú_execute_post_hookszCronTask._execute_post_hooksô   s'   € à×!Ò!ØˆIà×!Ñ!×4Ñ4°WÓ=Ð=r!   c                 ó–  — | j                  «        | j                  «       s1t        d| j                  t        j
                  k7  rd¬«      S d¬«      S | j                  d¬«      }	 | j                  |«       d}	 | j!                  «       5  | j#                  «       | _        | j$                  j&                  }| j                  ||j(                  ¬«      }	 | j+                  «       }| j$                  j-                  |j.                  |j0                  |j2                  ¬«       | j5                  |«      }|r=t        j                  d	| j                  › d|D �cg c]  }|j2                  ‘Œ c}› �«       |j.                  s| j7                  |«       |j.                  s | j9                  «       r| j;                  «        |j.                  s|j<                  r|j<                  ‚|cddd«       S # t        $ rz}t        |d|j                  j                  «      }t        |«      }t        |di «      }t        j                  d	| j                  › d
|› d|› �«       t        d|||¬«      cY d}~S d}~ww xY wc c}w # t>        t        f$ rš}tA        |t>        «      s| jC                  |«      nd}t        |«      }| j$                  r| j$                  jE                  ||¬«       | j7                  t        d||¬«      «       | j9                  «       r| j;                  «        ‚ d}~ww xY w# 1 sw Y   yxY w# tF        $ r ‚ t>        t        f$ �r}|�ý	 tH        jJ                  jM                  |¬«       ‚ # tH        jN                  $ rÅ tA        |t>        «      s| jC                  |«      nd}t        |«      }tQ        jR                  «       5  tH        jJ                  jU                  | jV                  | j                  | jX                  t[        j\                  «       dd||t_        j`                  «       ¬«	       ddd«       Y ‚ # 1 sw Y   Y ‚ xY ww xY w‚ d}~ww xY w)z5Main execution method with full lifecycle management.TzAlready executedÚSkipped)r   r   N)r   r   Údetailsrl   z rejected by PRE hook: z - F)r   r   r   r   )r€   rk   z& completed but POST hooks had errors: ÚTIMEOUT)r   r   )Úpk)	r.   r-   r4   rQ   rF   r   r   r   Úended)1rA   rM   r   r/   r   rG   rƒ   rˆ   r)   Úgetattrrr   r#   r(   rd   re   r-   rO   rU   r8   Úidr€   rY   Úmark_completedr   r   r   r‹   r}   ru   r{   r   r^   r>   ro   Úmark_failedr   r   rI   r;   ÚDoesNotExistr	   ÚatomicrR   r.   r4   rS   rT   r   Únow)	r   r„   rp   r   r~   Úerror_detailsr   rh   Úpost_hook_errorss	            r   ÚrunzCronTask.runû   sò  € ð 	�‰Œð �‰Ô Ü"ØØ-1×-CÑ-CÔGW×G^ÑG^Ò-^Ð)ôð àdmôð ð ×+Ñ+¸Ð+Ó>ˆð	Ø×#Ñ# GÔ,ð& ˆðZ	Ø×"Ñ"Õ$à!%×!=Ñ!=Ó!?�”Ø#Ÿ~™~×0Ñ0�ð ×3Ñ3°LÈ7×K[ÑK[Ð3Ó\�ð6à!×6Ñ6Ó8�Fð —N‘N×1Ñ1Ø &§¡Ø &§¡Ø#)×#4Ñ#4ð 2ô ð (,×'?Ñ'?ÀÓ'HÐ$Ù'ÜŸ™Ø# D§N¡NÐ#3Ð3YÙ6FÓGÑ6F° §£Ð6FÑGÐHðJôð "Ÿ>š>Ø×+Ñ+¨FÔ3ð "Ÿ>š>¨d×.?Ñ.?Ô.AØ×+Ñ+Ô-ð "Ÿ>š>¨f×.>Ò.>Ø$×.Ñ.Ð.à!÷O %Ñ$øô) ò 	ä   L°!·+±+×2FÑ2FÓGˆJÜ ›FˆMÜ# A y°"Ó5ˆMä�N‰NØ˜Ÿ™Ð'Ð'>¸z¸lÈ#ÈmÈ_Ð]ôô #ØØ%Ø%Ø"ô	õ ûð	üòX  Høô" %¤iÐ0ò Ü?IÈ!Ì\Ô?Z ×!4Ñ!4°QÔ!7Ð`i�JÜ$'¨£F�Mð —~’~ØŸ™×2Ñ2Ø$1Ø'1ð 3ô ð
 ×'Ñ'¬Ø %Ø -Ø#-ô)ô ð ×(Ñ(Ô*Ø×+Ñ+Ô-àûð+ú÷S %Ð$ûô~ (ò 	àÜœiÐ(ó 	àÐ'ðä!×)Ñ)×-Ñ-°Ð-Ô>ð$ øô# %×1Ñ1ò ä?IÈ!Ì\Ô?Z ×!4Ñ!4°QÔ!7Ð`i�JÜ$'¨£F�MÜ$×+Ñ+Õ-Ü%×-Ñ-×4Ñ4Ø&*§n¡nØ&*§n¡nØ+/×+>Ñ+>Ü "§	¡	£Ø&*Ø$)Ø$1Ø'1Ü"*§,¡,£.ð 5ô 
÷ .Ð-ð ÷ .Ð-ð úð#úð" ûð/	úsÍ   Á%G' Á9L* Â	A	LÃB I2ÅI-Å&A7I2Ç	L* Ç'	I*Ç0A/I%ÉI*É%I*É-I2É2LÊBLÌLÌLÌL'Ì#L* Ì'L* Ì*QÍQÍ M'Í&QÍ'AP?Î<A+P1Ð'P?Ð/QÐ1P;Ð6P?Ð9QÐ;P?Ð?QÑQr   c                  ó   — y)aV  
        Business logic - must be implemented by subclasses.
        
        Args:
            date: Execution date
            
        Returns:
            dict with keys:
                - error: bool (True if error occurred)
                - message: str (status message)
                - error_code: str (optional error code)
        Nr*   )r   r   s     r   rm   zCronTask.executez  s   € ð 	r!   )NN),r#   r$   r%   r&   r-   r(   Ú__annotations__r.   r   ÚSTANDARDr/   r0   r'   r1   Úintr2   r3   r   r   r    rA   rM   rO   r   rU   r   rY   rW   rX   r)   ro   ru   r{   r}   r   r   r   rƒ   rˆ   r‹   r›   r   rn   rm   r*   r!   r   r,   r,   %   s`  … Ù1à€IˆsÓØ€IˆsÓØ-×6Ñ6Ð�sÓ6Ø"Ð�dÓ"Ø€K�ÓØ€K�ÓØ!€GˆX�c‰]Ó!ð? tó ?òlð
˜Dó òBAð
¨ó 
ð oó ð¨oó ð6˜/ó ð@,¨	ð ,°có ,ð˜dó ò
ðU _ó Uñ
°¸#±ð 
ÐQYÐZ^Ð_bÐdgÐ_gÑZhÑQið 
ð  vHó 
ð	Ð*<ó 	ð>Ð+=ó >ð}�_ó }ð~ ð˜Dð  Tò ó ñr!   r,   )&r&   ÚloggingrS   rc   Úabcr   r   Údatetimer   Útypingr   r   r   Ú	django.dbr	   Údjango.confr
   Údjango.utilsr   Údjango_cronjob_utils.modelsr   Údjango_cronjob_utils.registryr   Údjango_cronjob_utils.locksr   Údjango_cronjob_utils.exceptionsr   r   Ú"django_cronjob_utils.notificationsr   Údjango_cronjob_utils.hooksr   r   Ú	getLoggerr#   rd   r   r,   r*   r!   r   Ú<module>r®      sf   ðñó Û 	Û ß #Ý ß &Ñ &Ý !Ý  Ý !Ý 5Ý :Ý 3ß UÝ Bß Zà	ˆ×	Ñ	˜8Ó	$€÷
ñ 
ôcˆsõ cr!   