o
    PCVj}  ã                   @   s”   d 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 ddlm	Z	 e	e
ƒ ¡ jjd Zddd	„Zd
e	defdd„Zeddedefdd„ƒZdS )u¨  
Garantiza que solo una instancia de un script corra a la vez.

ImplementaciÃ³n basada en fcntl.flock (lock advisory del kernel Linux):
  - Si el proceso que tiene el lock muere por cualquier motivo (crash,
    excepciÃ³n no capturada, kill -9, reboot), el kernel libera el lock
    automÃ¡ticamente al cerrar el file descriptor. NO quedan locks
    huÃ©rfanos que bloqueen ejecuciones futuras.
  - Si una segunda instancia intenta arrancar mientras la primera estÃ¡
    viva, sale inmediatamente sin tocar nada.

Uso tÃ­pico:

    from helpers.singleton import single_instance

    if __name__ == "__main__":
        with single_instance("procesar_output"):
            main()

Para inspeccionar a mano quÃ© scripts estÃ¡n corriendo:

    ls -la .locks/
    cat  .locks/procesar_output.lock     # muestra PID + hora de inicio

Para ver el proceso vivo:

    ps -p $(awk -F= '{print $2}' .locks/procesar_output.lock | awk '{print $1}')
é    N)Úcontextmanager)Údatetime)ÚPathz.locksÚreturnc                   C   s   t jddd� d S )NT)ÚparentsÚexist_ok)ÚLOCK_DIRÚmkdir© r
   r
   ú=/home/develop/edictos_py/central_edictos/helpers/singleton.pyÚ_ensure_lock_dir+   s   r   Ú	lock_pathc                 C   s(   z	| j dd� ¡ W S  ty   Y dS w )Nzutf-8)Úencodingz(no se pudo leer))Ú	read_textÚstripÚ	Exception)r   r
   r
   r   Ú_read_lock_info/   s
   ÿr   TÚnameÚexit_if_runningc                 c   s  � t ƒ  t| › d� }t|dƒ}zt | ¡ tjtjB ¡ W n- tyK   t	|ƒ}d| › d|› d|› d�}| 
¡  |rGt|tjd� t d¡ t|ƒ‚w | d¡ | ¡  | d	t ¡ › d
t ¡ jdd�› dttjd ƒj› d�¡ | ¡  t ¡ }zKdV  W t ¡ | }zt | ¡ tj¡ W | 
¡  z| ¡  W n ty£   Y nw | 
¡  z| ¡  W w  ty·   Y w w td| › d|d›d�ƒ dS t ¡ | }zt | ¡ tj¡ W | 
¡  z| ¡  W n tyê   Y nw | 
¡  z| ¡  W w  tyþ   Y w w td| › d|d›d�ƒ w )zã
    Adquiere un lock exclusivo identificado por `name`.

    Si ya hay otra instancia corriendo:
      - exit_if_running=True (default): imprime mensaje y hace sys.exit(0)
      - exit_if_running=False: lanza RuntimeError
    z.lockza+ú[z(] Ya hay una instancia corriendo. Lock: z	 | Info: z. Saliendo.)Úfiler   zpid=z	 started=Úseconds)Útimespecz script=Ú
Nz] lock liberado (z.1fzs)) r   r   ÚopenÚfcntlÚflockÚfilenoÚLOCK_EXÚLOCK_NBÚBlockingIOErrorr   ÚcloseÚprintÚsysÚstderrÚexitÚRuntimeErrorÚseekÚtruncateÚwriteÚosÚgetpidr   ÚnowÚ	isoformatr   Úargvr   ÚflushÚtimeÚLOCK_UNÚunlinkÚFileNotFoundError)r   r   r   ÚfpÚinfoÚmsgÚstartedÚelapsedr
   r
   r   Úsingle_instance6   s‚   €	
ÿÿÿ
ö
ÿþÿÿýÿ÷ÿýÿr9   )r   N)T)Ú__doc__r   r*   r#   r0   Ú
contextlibr   r   Úpathlibr   Ú__file__ÚresolveÚparentr   r   Ústrr   Úboolr9   r
   r
   r
   r   Ú<module>   s    
