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.socket
diz 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 journalctl
que Y foi iniciado e a saída de depuração com a data.
Ler sobreativação de soquetee2ºdo homem que o inventou.
Responder2
systemd lida com este caso comarquivos de soquete.
Um arquivo de unidade systemd nomeado some-socket.socket
seria criado para representar o soquete.
Então seu Service X
arquivo 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.