我有一个使用 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
这里有三个选项:
- 一起启动/停止两个装置。这不是最好的解决方案,因为它要求您记住这样做。
sudo systemctl stop foo.{service,socket}
- 仅管理服务。这需要您:
- 放下
[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
并且套接字将始终保持同步。
- 仅管理套接字。我更喜欢这个选项,因为服务仅在数据到达套接字时才开始运行。去做这个:
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