Запускать службу systemd только *после* прослушивания целевого сокета?

Запускать службу systemd только *после* прослушивания целевого сокета?

У меня есть служба X, которая должна подключаться к прослушивающему сокету при запуске. Этот целевой сокет сам по себе открыт другой службой Y, запущенной systemd.

Есть ли способ указать в файле модуля (или иным образом), что служба X должна запускаться только после того, как служба Y успешно запущена и открыла прослушивающий сокет?

Обратите внимание, что я не могу изменить службу X для повторной попытки, если первоначальное соединение не удалось. Также фиксированные задержки тоже не работают, потому что службе Y требуется разное количество времени, прежде чем она откроет прослушивающий сокет.

решение1

systemd работает немного по-другому. Вы настраиваете systemd для создания и прослушивания сокета, и если кто-то вроде X попытается подключиться, systemd запускает Y для обработки соединения, передавая ему сокет. Поэтому X может запуститься теоретически до Y, но это не будет иметь значения. Более поздние соединения будут обрабатываться Y. (Вы также можете настроить его так, чтобы Y перезапускался для каждого соединения, но я предполагаю, что это не ваш случай).

Минимальные изменения в Y заключаются в том, чтобы он принимал заранее созданный сокет в качестве своего файлового дескриптора stdin/stdout вместо того, чтобы выполнять создание/привязку самостоятельно.

Вот тестовая настройка, которую вы можете попробовать, не как root. Вам нужно 3 файла юнитов. ~/.local/share/systemd/user/mysock.socketсообщает systemd о необходимости создания сокета и о том, как его передать:

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

~/.local/share/systemd/user/mysock.service(имея то же имя mysock) — это служба, которая будет запущена, если кто-то подключится к сокету. Здесь вы запускаете Y, который я заменил на какой-то python.

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

Наконец, ваш X-сервис имеет Unit, который говорит, что ему требуется сокет. Для X я использую socat, который записывает дату в сокет. ~/.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 берет сокет на stdin, т. е. файловый дескриптор 0, и оборачивает его в подходящий объект сокета Python, выполняет операцию accept()и может читать/писать в него: ~/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()

После этого systemctl --user daemon-reloadвы сможете запустить X с помощью

systemctl --user start mysockdepend

и посмотрите в логах, journalctlчто Y был запущен, и отладочный вывод с датой.

Прочитать оактивация сокетаи2-йот человека, который его изобрел.

решение2

systemd обрабатывает этот случай с помощьюфайлы сокетов.

some-socket.socketДля представления сокета будет создан файл модуля systemd с именем .

Затем ваш Service Xфайл службы может включать After=директиву, ссылающуюся на сокет.

Официальная документация systemd по файлам сокетов должна оказаться полезной.

Связанный контент