简体   繁体   English

git post-receive挂钩未在后台运行

[英]git post-receive hook not running in background

According to the git documentation the post-receive hook essentially blocks the repo until it is completed: 根据git文档 ,post-receive钩子实质上阻塞了仓库,直到它完成:

... 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. 例如,运行脚本时,构建服务器无法从存储库中获取。

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 . 我们还假设您完全没有能力将脚本放置在git服务器上,而整个nohup /usr/bin/env python /path/to/post_receive.py 2>&1 > /dev/null &这个问题类似的方法。

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. 我们还假设您已经尝试了整个double os.fork() 'ing守护进程,与类似,还有其他一些问题(下面的示例代码无效 ),发现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)

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? 那么,在这些限制下,有人能成功运行长时间运行的python post-receive钩子,而该钩子实际上在后台运行而不阻塞存储库吗?

EDIT 编辑

working minimal structure with no exception handling... thanks to @torek and @jthill 工作最小的结构,没有异常处理...感谢@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()

You need to close down all descriptor access, so that ssh knows it will never get any more data. 您需要关闭所有描述符访问,以便ssh知道它将永远不会再获得任何数据。 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). 换句话说,在描述符0到2上调用os.close 。实际上,您需要将其打开 ,因此最好将os.devnullos.dup2的结果描述符打开到0、1和2上(以实现真正的健壮性)软件确保os.open尚未返回值0 <= fd <= 2当然,如果是,那就没关系,只需将其放在适当的位置,然后将其余的值os.open

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM