git post-receive挂钩未在后台运行 [英] git post-receive hook not running in background

查看:142
本文介绍了git post-receive挂钩未在后台运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 git文档的帖子-receive钩子实际上会阻止存储库,直到完成:

According to the git documentation the post-receive hook essentially blocks the repo until it is completed:

...客户端直到完成后才断开连接,因此,如果您尝试执行可能需要很长时间的任何操作,请务必小心.

... the client doesn’t disconnect until it has completed, so be careful if you try to do anything that may take a long time.

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

This causes a problem if you need the hook to kick off a build job and then poll for it's completion before kicking off another, say deploy, job. For example, the build server cannot fetch from the repo while said script is running.

我们还假设您完全无法将脚本放置在git服务器上,无法像完整的nohup /usr/bin/env python /path/to/post_receive.py 2>&1 > /dev/null &方法一样作为shell命令执行,而使用

Let's also assume that you have absolutely no ability to place your script on the git server to be executed as a shell command with the whole nohup /usr/bin/env python /path/to/post_receive.py 2>&1 > /dev/null & approach similar to this question.

我们还假设您已经尝试了整个os.fork()'ing双重守护进程,类似于 和其他一些问题(下面的不起作用示例代码),发现git在完成钩子之前仍要等待运行时间较长的子项完成.

Let's also assume that you have tried the whole double os.fork()'ing daemon process similar to this and a few other questions (non-working sample code below) and found that git still waits for the long-running child to finish before completing the hook.

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钩子,而该钩子实际上在后台运行而不会阻止回购吗?

So, with these constraints, has anyone been successful with a long running python post-receive hook that actually runs in the background without blocking the repo?

编辑

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

working minimal structure with no exception handling... thanks to @torek and @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()

推荐答案

您需要关闭所有描述符访问,以便ssh知道它将永远不会再获得任何数据.换句话说,在描述符0到2上调用os.close.实际上,您需要将它们设为 open ,因此最好在0、1上打开os.devnullos.dup2生成的描述符,和2(对于真正强大的软件,请确保os.open尚未返回值0 <= fd <= 2,当然-如果已返回,就可以了,只需将其保留在原来的位置,同时将其余部分进行重复处理即可.)

You need to close down all descriptor access, so that ssh knows it will never get any more data. In other words, call os.close on descriptors 0 through 2. In practice you need those to be open though, so it's better to open os.devnull and os.dup2 the resulting descriptor over 0, 1, and 2 (for truly robust software make sure os.open doesn't already return a value 0 <= fd <= 2, of course—if it does, that's OK, just keep it in place while dup2-ing the rest).

(您还需要通常的双叉把戏,并且明智的做法是放弃会话ID等.在某些基于Unix的系统中,有一个名为daemon的库例程,该例程可能位于libc或libutil可以为您完成所有这些工作,某些细节不可避免地取决于操作系统,例如放弃控制终端的方式(如果有的话),但是,链接的Python特定答案中缺少的主要内容是替换了stdin/stdout/stderr描述符.)

(You still also need the usual double-fork trick, and it may be wise to ditch session IDs and so on. In some Unix-derived systems there is a library routine called daemon, which may be in libc or libutil, that does all this for you. Some details are inevitably OS-dependent, such as the way to give up the controlling terminal if any. However, the main thing missing from your linked Python-specific answer is the replacement of the stdin/stdout/stderr descriptors.)

这篇关于git post-receive挂钩未在后台运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆