Systemd:如何正确重新启动服务/套接字

Systemd:如何正确重新启动服务/套接字

我有一个使用 Django 和 Gunicorn / Uvicorn 的相当简单的 Web 服务:

foo.service

[Unit]
Description=Foo service
Requires=foo.socket
After=network.target

[Service]
User=foo
Group=www-data
Restart=on-failure
WorkingDirectory=/var/lib/foo/current/backend
ExecStart=/var/lib/foo/.local/bin/poetry run gunicorn \
--env DJANGO_SETTINGS_MODULE=foo.settings \
--capture-output \
--log-level info \
--bind unix:/run/foo.sock \
--worker-class uvicorn.workers.UvicornWorker \
--workers 4 \
foo.asgi:application

[Install]
WantedBy=multi-user.target

foo.socket

[Unit]
Description=Foo socket
[Socket]
ListenStream=/run/foo.sock
[Install]
WantedBy=sockets.target

我已启用并启动了该服务。当我重新部署应用程序时,我正在迁移数据库并执行其他操作,在此期间我需要应用程序处于离线状态。但是当我发出:

sudo systemctl restart foo.service

我收到这条消息

Warning: Stopping foo.service, but it can still be activated by:
  foo.socket

我应该重新启动套接字吗?禁用服务并仅启用套接字? (该套接字又被 nginx 使用)。这里的最佳实践是什么?我不希望在迁移数据库时通过套接字激活该服务。

答案1

这里有三个选项:

  1. 一起启动/停止两个装置。这不是最好的解决方案,因为它要求您记住这样做。
sudo systemctl stop foo.{service,socket}
  1. 仅管理服务。这需要您:
    • 放下[Install]插座部分。这是不需要的,因为服务已经是Requires=套接字了。当服务启动时,socket也会启动。
    • 添加PartOf=foo.service到套接字[Unit]部分。这意味着当foo.service停止或重新启动时,该命令将传播到套接字。
# foo.service
[Unit]
Requires=foo.socket
After=network.target

[Service]
...

[Install]
WantedBy=multi-user.target

#foo.socket
[Unit]
PartOf=foo.service
[Socket]
ListenStream=/run/foo.sock

现在您可以sudo systemctl {restart,stop,start} foo.service并且套接字将始终保持同步。

  1. 仅管理套接字。我更喜欢这个选项,因为服务仅在数据到达套接字时才开始运行。去做这个:
    • Requires=从服务中删除。由于我们不直接启动服务,因此不需要这个。
    • [Install]从服务中删除该部分。我们将改为依赖套接字。
    • 添加PartOf=foo.socket到服务[Unit]部分。如果您的应用程序EOF在 stdin 或 stdout 上退出,则可能不需要此操作。
    • 添加StandardInput=socket[Service]您的服务部分。这并不是绝对必要的,但systemctl start foo.service如果套接字未启动,则会失败。
# foo.service
[Unit]
PartOf=foo.socket
After=network.target

[Service]
StandardInput=socket
...


#foo.socket
[Socket]
ListenStream=/run/foo.sock
[Install]
WantedBy=sockets.target

相关内容