Iniciar um serviço systemd somente *depois* que o soquete de destino estiver escutando?

Iniciar um serviço systemd somente *depois* que o soquete de destino estiver escutando?

Eu tenho um serviço X que precisa se conectar ao soquete de escuta quando for iniciado. Esse soquete de destino é aberto por outro serviço Y iniciado pelo systemd.

Existe alguma maneira de especificar no arquivo da unidade (ou de outra forma) para iniciar o serviço X somente após o serviço Y ter iniciado com sucesso e aberto o soquete de escuta?

Observe que não posso alterar o serviço X para tentar novamente se a conexão inicial falhar. Além disso, atrasos fixos também não funcionam bem porque o serviço Y leva vários períodos de tempo antes de abrir o soquete de escuta.

Responder1

systemd tende a funcionar de maneira um pouco diferente. Você configura o systemd para criar e escutar no soquete, e se alguém como X tentar se conectar, o systemd inicia Y para lidar com a conexão, passando-a pelo soquete. Portanto, X pode começar teoricamente antes de Y, mas isso não importa. As conexões posteriores serão tratadas por Y. (Você também pode configurá-lo para que Y seja reiniciado para cada conexão, mas presumo que não seja o seu caso).

As alterações mínimas em Y são para que ele aceite o soquete pré-criado como seu descritor de arquivo stdin/stdout, em vez de criar/vincular em si.

Aqui está uma configuração de teste que você pode tentar, não como root. Você precisa de 3 arquivos de unidade. ~/.local/share/systemd/user/mysock.socketdiz ao systemd para criar o soquete e como passá-lo:

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

~/.local/share/systemd/user/mysock.service(com o mesmo nome mysock) é o serviço que será iniciado caso alguém se conecte ao soquete. É aqui que você inicia Y, que substituí por algum python.

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

Finalmente, seu serviço X possui uma Unidade informando que requer o soquete. Para XI estou usando um socat que grava a data no soquete. ~/.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

O python pega o soquete em stdin, ou seja, o descritor de arquivo 0, e o envolve em um objeto de soquete python adequado, faz um accept()e pode ler/gravar nele: ~/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()

Depois de a systemctl --user daemon-reload, você poderá executar o X com

systemctl --user start mysockdepend

e veja nos logs journalctlque Y foi iniciado e a saída de depuração com a data.

Ler sobreativação de soqueteedo homem que o inventou.

Responder2

systemd lida com este caso comarquivos de soquete.

Um arquivo de unidade systemd nomeado some-socket.socketseria criado para representar o soquete.

Então seu Service Xarquivo de serviço pode incluir uma After=diretiva que faz referência ao soquete.

A documentação oficial do systemd sobre arquivos de soquete deve ser útil.

informação relacionada