偶尔停止使用它的 systemd 服务时systemctl stop test-server
会失败,提示作业已被取消:
Unable to stop service test-server: Job for test-server.service canceled.
什么可能导致服务停止被取消?
注意:停止实际上是从 Ansible playbook 启动的,但看不出它是如何相关的。
偶尔停止使用它的 systemd 服务时systemctl stop test-server
会失败,提示作业已被取消:
Unable to stop service test-server: Job for test-server.service canceled.
什么可能导致服务停止被取消?
注意:停止实际上是从 Ansible playbook 启动的,但看不出它是如何相关的。
systemd 中的每个单元在内部都有一个作业槽,并且一次只能为该单元安装一个作业。作业一般封装了单位的状态更改请求,但其效果因单位类型而异。在服务中,它们可能会启动状态更改请求,但即使您取消已安装的作业(或取消并替换为另一种作业类型,这将使另一个作业类型保持等待状态,直到该操作完成,该操作仍可能运行,因为unit_start/stop 函数内部也可以决定某个作业何时可运行)。
例如,如果您有一个需要很长时间的停止操作,则在停止作业运行时调用 start 将使用默认作业模式(替换)取消已安装/正在运行的停止作业,并在单元的职位空缺。由于 unit_stop 之前已经启动了到 deactivating 的转换(以及映射到服务内部子状态的任何内容 - stop、stop-sigterm、stop-sigkill、stop-final、stop-final-sigterm、stop-final-sigkill),unit_start 现在将return -EAGAIN,这导致 systemd 将启动作业置于 JOB_WAITING 状态,并在下一次状态更改时将其添加到运行队列中,检查是否再次可运行,并根据结果再次运行或进入等待状态(来自单元通知)。每次运行作业时,它都会从运行队列中删除。
这是这里对一些活动部分的概述。关于作业需要记住三件事:它们有一个类型(开始、停止、重新启动、重新加载等)、一个结果(超时、完成、取消、依赖、跳过等)和一个模式(替换、隔离、冲洗等)。模式适用于整个事务(所请求的作业及其要求以及以一致方式一起应用的传播相关作业),有关于它们各自做什么的文档。
在您的特定情况下,似乎当您执行 systemctl stop 时,另一个作业进入并替换您的停止作业,并且 systemctl 客户端断开连接,因为它排队的作业被取消。这可能是由于某种依赖性,或其他原因(如 ExecStop= 最终调用 systemctl start 单元(仅在第一次工作)或类似的东西,或者想要/要求/绑定到同一单元的单元启动触发启动替换您触发的停止作业的作业等)。它可能是一个被套接字激活的服务,并且由于连接繁忙,被重新触发,由于套接字单元中的 Triggers= 依赖项将启动作业排入队列,从而取消您的停止作业。它也可能是一个计时器或其他东西:简而言之,由于其他一些工作进入并替换它,停止工作正在被替换。
当然,正如您所注意到的,这一切都容易发生比赛,它可能会发生也可能不会发生,所以在您的情况下偶尔会发生。最好检查您的设置以避免这些问题。
就我而言,我得到了
原因是我已经将 nginx 定义
BindsTo=
为拥有另一个服务,以便它在另一个服务运行时准确运行。由于一个bug,某天另一个服务立即开始退出,导致systemd取消了nginx的启动作业。
不幸的是,systemd 似乎没有进一步说明取消的原因——我觉得如果它这样做会更好(而且我已经要求它)。