我有一个服务 X,它需要在启动时连接到侦听套接字。该目标套接字本身由 systemd 启动的另一个服务 Y 打开。
有没有办法在单元文件(或其他方式)中指定仅在服务 Y 成功启动并打开侦听套接字后才启动服务 X?
请注意,如果初始连接失败,我无法将服务 X 更改为重试。固定延迟也不能很好地工作,因为服务 Y 在打开侦听套接字之前需要不同的时间。
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
Run Code Online (Sandbox Code Playgroud)
~/.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
Run Code Online (Sandbox Code Playgroud)
最后,您的 X 服务有一个 Unit 说它需要套接字。对于 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
Run Code Online (Sandbox Code Playgroud)
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()
Run Code Online (Sandbox Code Playgroud)
在 a 之后systemctl --user daemon-reload,您应该能够使用 X 运行
systemctl --user start mysockdepend
Run Code Online (Sandbox Code Playgroud)
并在日志中journalctl看到 Y 已启动,以及带有日期的调试输出。
| 归档时间: |
|
| 查看次数: |
8473 次 |
| 最近记录: |