【问题标题】:git post-receive hook not running in backgroundgit post-receive 钩子不在后台运行
【发布时间】:2017-01-05 20:32:20
【问题描述】:

根据git documentation,post-receive 钩子实际上会阻塞 repo,直到它完成:

...客户端在完成之前不会断开连接,因此如果您尝试执行任何可能需要很长时间的操作,请小心。

如果您需要钩子来启动构建作业,然后在启动另一个(例如部署)作业之前轮询它的完成,这会导致问题。例如,当所述脚本运行时,构建服务器无法从 repo 中获取。

我们还假设您完全没有能力将您的脚本放在 git 服务器上,以使用类似于 this question 的整个 nohup /usr/bin/env python /path/to/post_receive.py 2>&1 > /dev/null & 方法作为 shell 命令执行。

我们还假设您已经尝试了类似于this 的整个双重os.fork()'ing 守护进程和一些其他问题(non-working 示例代码如下)并发现 git 仍然在完成钩子之前等待长时间运行的孩子完成。

pid = os.fork()
if pid == 0:
    os.setsid()
    pid = os.fork()
    if pid == 0:
        long_running_post_receive_function()
    else:
        os._exit(0)
else:
    for fd in range(0, 3):
        os.close(fd)
    os._exit(0)

那么,在这些限制条件下,有没有人成功地使用了一个长时间运行的 python post-receive 钩子,该钩子实际上在后台运行而不会阻塞 repo?

编辑

工作最小的结构,没有异常处理......感谢@torek和@jthill

pid = os.fork()
if pid == 0:
    os.setsid()
    pid = os.fork()
    if pid == 0:
        for fd in range(0, 3):
            os.close(fd)
        long_running_post_receive_function()
    else:
        os._exit(0)
else:
    sys.exit()

【问题讨论】:

  • 您还可以使用某种生产者/消费者模型,其中 post-receive 挂钩发送某种“异步消息”(可能就像触摸文件一样简单),这会导致消费者守护进程注意这一点并做好它的工作。
  • 我当然同意这是一个替代方案,它确实违背了我想要完成的目标
  • 我很累,但在我看来,您的 dup2() 操作在错误的地方。 fd 在长时间运行的过程中仍处于打开状态。
  • @jthill 就是这样!谢谢!

标签: python linux git background-process


【解决方案1】:

您需要关闭所有描述符访问,以便 ssh 知道它永远不会再获取任何数据。换句话说,在描述符 0 到 2 上调用 os.close。实际上,您需要将它们 打开,因此最好打开 os.devnullos.dup2 得到的描述符超过 0、1 , 和 2(对于真正强大的软件,请确保 os.open 还没有返回值 0 <= fd <= 2,当然,如果确实如此,那没关系,只需将其保留在原位,同时 dup2-ing 其余部分)。

(您仍然需要通常的双叉技巧,放弃会话 ID 等可能是明智之举。在某些 Unix 派生系统中,有一个名为 daemon 的库例程,它可能位于 libc 或libutil,它为您完成所有这些。一些细节不可避免地取决于操作系统,例如放弃控制终端(如果有)的方式。但是,链接的 Python 特定答案中缺少的主要内容是替换标准输入/标准输出/标准错误描述符。)

【讨论】:

  • 除非我犯了错误或遗漏了什么,否则这似乎仍然不起作用。我已经用我尝试过的示例编辑了我的问题。
  • 这是什么意思!?!?
  • @JoeZim:这里有很多深(ish)的 Unix/Linux 特定的东西;您关心哪些部分?
  • @torek 起初我很困惑,因为它不起作用。我仔细阅读,现在我知道它是 Python 而不是 Bash 脚本。无论如何,我不明白我们closeing 是什么,但真正理解这一点并不重要。现在,我只是好奇是否有办法使用 Bash 而不是 Python 来做到这一点?
  • 您可以使用重定向从 shell 执行关闭操作。我们需要重新连接 stdout 和/或 stderr(无论哪个都连接到 ssh——通常两者都连接)的原因是客户端主机上运行的 ssh 正在等待“不再有数据到达”指示器通过通信链路(插座)。为了实现这一点,在 Unix 机器上,必须有 no 可以通过该套接字提供输入的打开文件描述符。因此,如果我们执行longrunningcmd </dev/null >/dev/null 2>&1 &,我们会确保longrunningcmd 不会保持 fd 的打开状态。
猜你喜欢
  • 2013-02-02
  • 2017-10-19
  • 2012-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-24
  • 2014-05-13
相关资源
最近更新 更多