systemd oneshot 要求只执行一次

systemd oneshot 要求只执行一次

我有多个 systemd 服务需要生成的环境文件。我有一个生成此环境文件的 shell 脚本,但因为我需要该环境文件执行任何 Exec... 命令,我无法使用 ExecStartPre=generate_env_file.sh 。因此,我设置了另一个服务(generate_env_file.service)来一次性运行该脚本:

[Service]
Type=oneshot
ExecStartPre=/usr/bin/touch /path/to/config.ini
ExecStart=/path/to/generate_env_file.sh

我还有多个其他服务文件,其中包含:

[Unit]
Requires=generate_env_file.service
After=generate_env_file.service

如何保证两个或多个依赖服务(需要generate_env_file.service)不会并行运行并生成两个并行执行的generate_env_file.service?

我已经考虑过使用 RemainAfterExit=true 或可能的 StartLimitIntervalSec= 和 StartLimitBurst= 来确保在一段时间内一次只会执行一个副本,但我不确定执行此操作的最佳方法。

答案1

RemainAfterExit=true是要走的路。在这种情况下,Systemd 启动服务,并且 Systemd 认为它已启动并处于活动状态。然而,这并不涵盖执行的用例systemctl restart generate_env_file.service。在这种情况下,systemd 将重新执行您的服务。为了解决这个问题,您可以在运行文件系统中创建一个标记文件ExecStartPost=并添加ConditionPathExists=指令检查文件是否存在。

答案2

ConditionFirstBoot可能也很有趣:

采用布尔参数。该条件可用于根据系统是否第一次启动来确定单元的条件。这大致意味着/etc/系统开始启动时未填充(有关详细信息,请参阅《首次启动语义》 机器 ID(5))。管理器完成启动阶段后,首次启动被视为已完成(此条件将评估为 false)。

此条件可用于/etc/在恢复出厂设置后首次启动时填充,或者在新系统实例首次启动时填充。

为了鲁棒性,单位ConditionFirstBoot=yes应该先命令自己first-boot-complete.target并用 拉入这个被动目标Wants=。这确保了在首次启动中止的情况下,这些单元将在下次系统启动期间重新运行。

如果systemd.condition-first-boot=在内核命令行上指定了该选项(采用布尔值),它将覆盖此条件检查的结果,优先于/etc/machine-id 存在检查。

答案3

更新generate_env_file.sh以在启动后立即检查锁定文件是否存在。如果锁定文件存在,则立即退出。

如果不存在锁定文件,请立即触摸锁定文件,然后执行生成配置文件的操作,然后删除锁定文件。

换句话说,我认为没有systemd一种本机方法可以处理您通过配置描述的情况,因此请使用锁定文件。

正如 @shellter 指出的那样,Unix 站点是一个更适合systemd将来提问的站点。

相关内容