起動時にリスニングソケットに接続する必要があるサービスXがあります。ターゲットソケット自体は、systemdによって開始された他のサービスYによって開きます。
サービスYが正常に起動し、リスニングソケットを開いた後にのみサービスXを起動するように単位ファイル(または他の手段)に割り当てる方法はありますか?
初期接続が失敗した場合、再試行するようにサービス 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サービスにはソケットが必要であることを示す単位があります。 XI の場合、 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は標準入力(ファイルディスクリプタ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が開始されたことを確認し、日付とともに出力をデバッグします。