防止 systemd 计时器在启动时运行

防止 systemd 计时器在启动时运行

我一直在将 crontab 迁移到 systemd 的计时器单元。它们看起来都类似于:

.计时器文件:

[Unit]
Description=timer that uses myjob.service

[Timer]
OnCalendar=*-*-* *:00:00
Unit=myjob.service

[Install]
WantedBy=timers.target

.服务文件:

[Unit]
Description=Script that runs myjob.sh

[Service]
ExecStart=/home/user/myjob.sh

我的计时器可以工作,但它们也会在系统重新启动时执行。我希望我的 OnCalendar 事件仅在指定时间运行,而不是在我重新启动电脑的任意时间运行。有任何想法吗?


更新:我通过将“用户”计时器转换为根/系统计时器解决了这个问题。

  1. 我禁用了所有 .service 和 .timer 文件,并将它们从我的主目录移到 /etc/systemd/system 中。

  2. 我将“User=”部分添加到每个服务文件中,以便我的脚本由普通用户而不是 root 运行。

现在,我的计时器在系统启动时没有被触发,并且当我通过 ssh 登录时,我也遇到了偶尔触发的问题。现在这个问题也已经解决了,因为它们受到 root 帐户的控制,但运行我的脚本仍然以普通用户的 PID 运行,这保留了我的文件的所有权属性。问题解决了。

答案1

我也遇到了同样的问题,无法弄清楚为什么单位总是在启动时运行,无论Persistent.timer 文件中的设置如何,我花了一段时间,但我终于找到了原因(@alexander-指出了正确的方向)托尔卡切夫的评论)。

问题是我总是WantedBy=basic.target在 .service 文件的 [Install] 部分中包含类似的内容(因为它是标准 systemd 服务复制意大利面的一部分)。事实证明,这实际上会导致该单元在 basic.target 启动时启动(也称为系统启动)。

https://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy= https://www.freedesktop.org/software/systemd/man/systemd.special.html#basic.target

我怀疑OP无意中通过禁用旧的 .service (您必须这样做才能删除由 .service 创建的符号链接WantedBy)并在重写时忽略 [Install] 部分或从不运行 来解决了他们的问题systemctl enable

太长了;您不希望 .service 文件中的 [Install] 部分由 .timer 文件触发。

答案2

其他答案中没有涵盖更多可能性......

可能性A

重新启动时,可能不是计时器启动服务,而是服务本身systemctl enable <service-unit>在之前的某个时刻安装/启用(即通过)。

例如,服务启动是因为您[Install]的服务单元中有一个部分并在过去的某个时刻启用了该服务。

可能性B

该服务可以运行,因为它被声明为某个其他单元的依赖项。

有一篇关于 cron 到 systemd 计时器的热门搜索结果博客文章,其中包含计时器执行Requires=myUnit.service.当计时器在启动时启动(应该如此)...因为计时器需要服务(依赖项),因此服务在计时器之前启动...即每次启动时。

去检查...

  • 重新启动,
  • 该服务刚刚在重新启动时运行吗? systemctl status <service-unit>
    • 如果没有,就没有问题,完成。
  • 是启动时运行服务的计时器吗?:systemctl list-timers
    • 检查您的服务的计时器。它刚刚运行/触发吗?
    • 如果是:则计时器触发服务运行。
      • 检查Persistent计时器单元中的设置 - 可能运行是因为计时器认为它错过了一次运行。
    • 如果不:
      • 确保计时器单元不依赖于您的服务(Requires=<service-unit>或类似的愚蠢的东西)
      • 可以grep -R <service-unit> /etc/systemd/system/查看其他单位是否正在引用或取决于您的服务。
      • 如果您的计时器(和其他单元)不依赖于您的服务......那么该服务可能由于之前安装/启用而运行。
  • 跑步systemctl is-enabled <service-unit>。如果它说static这意味着它未启用并且没有[Install]部分(好)。
    • 白痴通过运行find /etc/systemd/system/*.wants -name '<service-name>*'并确保没有从先前安装/启用来启动服务的剩余符号链接来检查这一点。
  • 如果由于某种原因启用了该服务...
    • 跑步systemctl disable <service-unit>
    • [Install]从服务单元中删除该部分
    • 运行systemctl --system daemon-reload以加载您的更改。
    • 重新启动并确认该服务(希望)不再在启动时运行。

使用计时器作为 cron 替代品的技巧...

  • 您不希望计时器为Requires=您服务。
  • 您不希望您的服务Wants=Requires=(等等)您的计时器。
  • 您应该[Install]在计时器单元中包含一个部分,以便它在启动时与其余计时器一起启动。
  • 您想要启用/启动计时器,以便其运行并在重新启动后再次开始运行。 (注意计时器运行并不意味着服务运行)。
  • 您不想要enable您的服务,也不应该[Install]在您的服务单元中包含一个部分。

我认为这里的许多“解决方案”都有效,因为人们在新位置/名称中重新创建了单元文件,而没有部分[Install]和/或没有运行systemctl enable <service-unit>.这有效但不是必需的。您只需systemctl disable <service-unit>在原始服务单元上运行即可,无需重新创建。

答案3

根据文档您应该将配置更改为Persistent=falsePersistent完全删除,因为默认情况下它是错误的。

答案4

在我自己的服务器上调查此问题时,我发现了以下内容:

$ systemctl status man-db.timer
Apr 09 08:10:00 anemone systemd[1]: man-db.timer: Not using persistent file timestamp Mon 2018-04-16 19:40:02 EDT as it is in the future.
Apr 09 08:10:00 anemone systemd[1]: Started Daily man-db cache update.

事实证明,板载 RTC 的电池没电了,因此系统以过去的日期启动(可能从文件系统中获取)。通过运行确认

journalctl --boot

并看到当前启动的日志有错误的时间戳。添加这个以防其他人的问题恰好与我的问题相符。

相关内容