Cuando una aplicación se detiene, es crucial controlar el graceful period para cerrar conexiones, finalizar tareas en curso, o liberar recursos. En este post, veremos cómo controlar este proceso en Python usando el paquete signals
.
¿Qué es el Graceful Shutdown y por qué es importante?
El graceful shutdown es el proceso de detener una aplicación de forma ordenada, permitiéndole completar tareas pendientes antes de finalizar. Esto es especialmente útil en servidores y sistemas en producción, donde una terminación abrupta puede causar pérdida de datos, conexiones interrumpidas o estados inconsistentes.
En mi día a día es habitual, ya que todas mis aplicaciones están desplegadas en Kubernetes, tener que controlar estos escenarios donde la aplicación puede rotar en cualquier momento. Por tanto es importante estar preparado para ccuando esto ocurra y que no sea un problema.
Al implementar un cierre controlado, podemos asegurarnos de que la aplicación libere recursos correctamente, cierre conexiones a bases de datos o tenga tiempo a terminar eventos en ejecución, mejorando la estabilidad y confiabilidad del sistema.
Graceful Shutdown custom en cualquier aplicacion Python
Implementar un graceful shutdown personalizado en Python nos permite adaptar el proceso de cierre a las necesidades específicas de nuestra aplicación.
Por suerte para nosotros implementar esto es bastante sencillo, ya que basta con hacer uso del paquete signal
para definir una función a ejecutar cuando ocurran ciertas señales de cierre en nuestra aplicación. Veamos un ejemplo:
from signal import signal, SIGTERM
from time import sleep
from typing import FrameType
from src.logger import Logger
logger = Logger()
def attach_sigterm_handler(_signal: int, _frame: FrameType | None) -> None:
logger.info("Graceful shutdown started....")
# Do whatever you need
sleep(5) # Sleep 5 seconds
events_processor.stop()
# Do whatever you need
logger.info("Graceful shutdown finished....")
signal(SIGTERM, attach_sigterm_handler)
events_processor = RabbitMQEventsProcessor(logger)
events_processor.start() # blocking process
En este código de ejemplo:
- Definimos el handler
attach_sigterm_handler
donde:- Emitimos un mensaje de inicio en el log.
- Aquí podemos ejecutar cualquier cosa que necesitemos antes del
sleep
. - Pausamos la ejecución por 5 segundos.
- Aquí podemos ejecutar cualquier cosa que necesitemos antes de acabar el
graceful shutdown
. - Detenemos el proceso bloqueante del procesador eventos llamado
events_processor
.
- Usamos la función
signal()
para capturar la señalSIGTERM
y ejecutarattach_sigterm_handler
, que se encarga de realizar las acciones necesarias antes de finalizar la aplicación. - Arrancamos el
RabbitMQEventsProcessor
con el metodostart
que es bloqueante y se queda corriendo hasta que en algún momento sea parado por el handler.
Este enfoque permite asegurarnos de que los procesos en ejecución, como la gestión de eventos de RabbitMQ, se detengan correctamente antes de que la aplicación termine, evitando pérdidas de mensajes o estados inconsistentes.
¡Espero que os haya gustado!