Tengo un proceso de servidor (lanzado desde systemd) que puede iniciar un proceso de actualización. El proceso de actualización se autodemoniza y luego (en teoría) mata el servidor con SIGTERM. Mi problema es que SIGTERM se propaga al proceso de actualización y sus hijos .
Para fines de depuración, el proceso de actualización simplemente duerme y envío la eliminación a mano.
Ejemplo de salida de PS antes de matar:
1 1869 1869 1869 ? -1 Ss 0 0:00 /usr/local/bin/state_controller --start 1869 1873 1869 1869 ? -1 Sl 0 0:00 \_ ProcessWebController --start 1869 1886 1869 1869 ? -1 Z 0 0:00 \_ [UpdateSystem] <defunct> 1 1900 1900 1900 ? -1 Ss 0 0:00 /bin/bash /usr/local/bin/UpdateSystem refork /var/ttm/update.bin 1900 1905 1900 1900 ? -1 S 0 0:00 \_ sleep 10000 Tenga en cuenta que UpdateSystem está en un PGID y TPGID separados. (El proceso <defunct> es el resultado de la demonización y no es (creo) un problema).
UpdateSystem es un script bash (aunque puedo convertirlo fácilmente en un programa C si eso ayuda). Después del código de demonización tomado de https://stackoverflow.com/a/29107686/771073 , lo interesante es:
############################################# trap "echo Ignoring SIGTERM" SIGTERM sleep 10000 echo Awoken from sleep - presumably by the SIGTERM exit 0 Cuando elimino kill 1869 (que envía SIGTERM al proceso del servidor state_controller , mi archivo de registro contiene:
Terminating Ignoring SIGTERM Awoken from sleep - presumably by the SIGTERM Realmente quiero evitar que SIGTERM se envíe al proceso de sleep .
(En realidad, realmente quiero evitar que se envíe a apt-get upgrade , que detiene el sistema a través del equivalente moral de systemctl stop ttm.service y ExecStop se especifica como /bin/kill $MAINPID , en caso de que eso cambie la responder.)
Esta pregunta es similar, pero la respuesta aceptada (use KillMode=process ) no funciona bien para mí: quiero eliminar algunos de los procesos secundarios, pero no el proceso de actualización: no se puede separar el proceso secundario cuando se inicia el proceso principal de systemd
Un enfoque completamente diferente es que el proceso de actualización se elimine del grupo de servicios actualizando el sistema de archivos /sys/fs/cgroup/systemd . Específicamente en bash:
echo $$ > /sys/fs/cgroup/systemd/tasks Un proceso pertenece exactamente a un grupo de control. Escribir su PID en el archivo de tasks raíz lo agrega al otro grupo de control y lo elimina del grupo de control de servicio.
Teníamos exactamente el mismo problema. Lo que terminamos haciendo es iniciar el proceso de actualización como cgroup transitorio con systemd-run :
systemd-run --unit=my_system_upgrade --scope --slice=my_system_upgrade_slice -E setsid nohup start-the-upgrade &> /tmp/some-logs.log & De esa forma, el proceso de actualización se ejecutará en un cgroup diferente y no finalizará. Además, usamos setsid + nohup para asegurarnos de que el proceso tenga su propio grupo y sesión y que el proceso principal sea el proceso de inicio.
El enfoque que hemos decidido adoptar es iniciar el proceso de actualización en un servicio separado (de un solo disparo). Como tal, pertenece automáticamente a un grupo de control separado, por lo que matar el servicio principal no lo mata.
Sin embargo, hay una arruga en esto. El paquete instala ttm.service y ttm.template.update.service . Para ejecutar el actualizador, copiamos ttm.template.update.service a ttm.update.service , ejecutamos systemctl daemon-reload y luego ejecutamos systemctl start ttm.update.service . ¿Por qué la copia? Porque cuando el actualizador instala una nueva versión de ttm.template.update.service , terminará por la fuerza cualquier proceso que se ejecute como ese servicio. KillMode=None parece ofrecer una solución, pero aunque parece funcionar, una llamada posterior a apt-get arroja un desagradable error sobre la interrupción de dpkg.