首页 > 解决方案 > 管道中的 python 进程返回异常后,Systemd 单元未失败

问题描述

我们有这个 systemd 单元,它在其ExecStart=指令中启动两个管道 python 进程。该单元的类型为: oneshot,并且当第一个 python 进程以某种方式引发异常时,该单元被放回inactive状态。

下面是我们的单位。它没有:[Install]部分,因为我们使用计时器触发它,或者手动使用systemctl start my-unit.service::

[Unit]
Description=Connector
Documentation=Docs
StartLimitInterval=600
StartLimitBurst=3

[Service]
Type=oneshot
User=user
Group=group
WorkingDirectory=/home/user/dir

ExecStartPre=bash -c 'echo "Pre"'
ExecStart=bash -c 'python_1 | python_2'
ExecStartPost=bash -c 'echo "Post"'

KillMode=control-group
KillSignal=SIGTERM

StandardOutput=append:/home/user/dir/out.log
StandardError=append:/home/user/dir/err.log

TimeoutSec=21600

Restart=on-failure
RestartSec=5
RemainAfterExit=false

从文档中 systemd 不支持管道,这就是为什么我们一直在运行包装在bash -c '...'命令中的整个事情。

我知道第一个 python 进程通过查看日志引发了异常:/home/user/dir/err.log. 这是第一个进程引发异常后单元的状态:

● my-unit.service - Connector
     Loaded: loaded (/etc/systemd/system/my-unit.service; static; vendor preset: enabled)
     Active: inactive (dead) since Tue 2021-05-11 14:48:24 UTC; 12s ago
TriggeredBy: ● my-unit.timer
    Process: 108838 ExecStartPre=/usr/bin/bash -c echo "Pre" (code=exited, status=0/SUCCESS)
    Process: 108839 ExecStart=/usr/bin/bash -c p1 | p2 (code=exited, status=0/SUCCESS)
    Process: 108973 ExecStartPost=/usr/bin/bash -c echo "Post" (code=exited, status=0/SUCCESS)
   Main PID: 108839 (code=exited, status=0/SUCCESS)

May 11 14:48:21 ip-10-11-0-81 systemd[1]: Starting Connector...
May 11 14:48:24 ip-10-11-0-81 systemd[1]: connector-mavenlink.service: Succeeded.
May 11 14:48:24 ip-10-11-0-81 systemd[1]: Finished Connector mavenlink.

我们通常对这个单元感到满意,这是它第一次出现故障,但我们真的希望它能够进入一个failed状态,因为我们有可观察性工具来监控它。

有什么想法吗?

谢谢!

标签: linuxpipesystemd

解决方案


所以我想我解决了我自己的问题,所以我会在这里写下来,并且可能会在我关闭它之前将它留在这里一段时间。确实感觉有点hacky。

status codeExecStart=指令的事实被认为是: 0systemd 让我想到了set -o pipefail我们用来使 bash 脚本将管道错误理解为全局错误的 bash 标志(措辞不佳,但我认为这就是它的要点)

所以我编辑了我们的单元以命令-o pipefail中添加标志,如下所示:bash -c '...'

[Unit]
Description=Connector
Documentation=Docs
StartLimitInterval=600
StartLimitBurst=3

[Service]
Type=oneshot
User=user
Group=group
WorkingDirectory=/home/user/dir

ExecStartPre=bash -c 'echo "Pre"'
ExecStart=bash -c 'set -o pipefail && python_1 | python_2'
ExecStartPost=bash -c 'echo "Post"'

KillMode=control-group
KillSignal=SIGTERM

StandardOutput=append:/home/user/dir/out.log
StandardError=append:/home/user/dir/err.log

TimeoutSec=21600

Restart=on-failure
RestartSec=5
RemainAfterExit=false

...这似乎有效:现在,当第一个 python 进程引发异常时,我们的单元被发送到一个:failed状态(在它按照我们的配置重新启动几次之后)。以下是更新failed状态:

● my-unit.service - Connector
     Loaded: loaded (/etc/systemd/system/my-unit.service; static; vendor preset: enabled)
     Active: failed (Result: exit-code) since Tue 2021-05-11 15:01:28 UTC; 1s ago
TriggeredBy: ● my-unit.timer
       Docs: Docs
    Process: 109454 ExecStartPre=/usr/bin/bash -c echo "Pre" (code=exited, status=0/SUCCESS)
    Process: 109463 ExecStart=/usr/bin/bash -c set -o pipefail && p1 | p2 (code=exited, status=1/FAILURE)
   Main PID: 109463 (code=exited, status=1/FAILURE)

May 11 15:01:28 ip-10-11-0-81 systemd[1]: my-unit.service: Scheduled restart job, restart counter is at 3.
May 11 15:01:28 ip-10-11-0-81 systemd[1]: Stopped Connector.
May 11 15:01:28 ip-10-11-0-81 systemd[1]: my-unit.service: Start request repeated too quickly.
May 11 15:01:28 ip-10-11-0-81 systemd[1]: my-unit.service: Failed with result 'exit-code'.
May 11 15:01:28 ip-10-11-0-81 systemd[1]: Failed to start Connector.

推荐阅读