¿Iniciar un servicio systemd solo *después* de que el socket de destino esté escuchando?

¿Iniciar un servicio systemd solo *después* de que el socket de destino esté escuchando?

Tengo un servicio X que necesita conectarse al conector de escucha cuando se inicia. Ese socket de destino es a su vez abierto por otro servicio Y iniciado por systemd.

¿Hay alguna forma de especificar en el archivo de la unidad (o de otra manera) iniciar solo el servicio X después de que el servicio Y haya iniciado y abierto exitosamente el socket de escucha?

Tenga en cuenta que no puedo cambiar el servicio X para volver a intentarlo si falla la conexión inicial. Además, los retrasos fijos tampoco funcionan bien porque el servicio Y tarda distintos tiempos antes de abrir el conector de escucha.

Respuesta1

systemd tiende a funcionar de manera ligeramente diferente. Usted configura systemd para crear y escuchar en el socket, y si alguien como X intenta conectarse, entonces systemd inicia Y para manejar la conexión, pasándole el socket. Entonces X puede comenzar teóricamente antes que Y, pero no importará. Las conexiones posteriores serán manejadas por Y. (También puede configurarlo para que Y se reinicie para cada conexión, pero supongo que ese no es su caso).

Los cambios mínimos en Y son hacer que acepte el socket creado previamente como su descriptor de archivo stdin/stdout, en lugar de realizar la creación/vinculación por sí mismo.

Aquí tienes una configuración de prueba que puedes probar, no como root. Necesitas archivos de 3 unidades. ~/.local/share/systemd/user/mysock.socketle dice a systemd que cree el socket y cómo transmitirlo:

# create listening socket. on 1st connect run mysock.service
[Socket]
ListenStream=5555
Accept=false

~/.local/share/systemd/user/mysock.service(que tiene el mismo nombre mysock) es el servicio que se iniciará si alguien se conecta al socket. Aquí es donde comienzas Y, que he reemplazado por Python.

[Unit]
Description=started from mysock.socket
[Service]
ExecStart=/home/meuh/bin/python/mysock.py
StandardInput=socket

Finalmente, su servicio X tiene una Unidad que dice que requiere el socket. Para X, estoy usando un socat que escribe la fecha en el socket. ~/.local/share/systemd/user/mysockdepend.service

[Unit]
Description=dependent on socket listening
Requires=mysock.socket
[Service]
ExecStart=/usr/bin/socat -U tcp:localhost:5555 exec:/usr/bin/date

Python toma el socket en la entrada estándar, es decir, el descriptor de archivo 0, y lo envuelve en un objeto de socket de Python adecuado, realiza una operación accept()y puede leerlo/escribirlo: ~/bin/python/mysock.py

#!/usr/bin/python
# started from /home/meuh/.local/share/systemd/user/mysock.service
# with socket on stdin/stdout
import sys, time, socket, subprocess

def debug(msg):
#    time.sleep(3)
    subprocess.call(["/usr/bin/logger", msg])

debug("start\n")
s = socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM)
while True:
    conn, addr = s.accept()
    conn.send("hello\n")
    while True:
        try:
            data = conn.recv(100)
            debug("got "+data+"\n")
            if len(data)<=0: break
        except:
            break
    conn.close()

Después de systemctl --user daemon-reload, deberías poder ejecutar X con

systemctl --user start mysockdepend

y vea en los registros journalctlque se inició Y y la salida de depuración con la fecha.

Leer acerca deactivación del enchufey2dodel hombre que lo inventó.

Respuesta2

systemd maneja este caso conarchivos de socket.

some-socket.socketSe crearía un archivo de unidad systemd llamado para representar el socket.

Entonces su Service Xarchivo de servicio puede incluir una After=directiva que haga referencia al socket.

La documentación oficial de systemd sobre archivos de socket debería ser útil.

información relacionada