根据git documentation,post-receive hook基本上阻止了repo直到它完成:
...客户端在完成之前不会断开连接,因此如果您尝试执行可能需要很长时间的任何操作,请务必小心。
如果您需要挂钩启动构建作业,然后在启动另一个(例如部署)作业之前轮询它的完成,则会导致问题。例如,在所述脚本运行时,构建服务器无法从存储库中获取。
我们还假设你完全没有能力将你的脚本放在git服务器上作为shell命令执行,整个nohup /usr/bin/env python /path/to/post_receive.py 2>&1 > /dev/null &
方法类似于this question。
我们还假设您已尝试过与this类似的整个双os.fork()
守护进程以及其他一些问题(非工作示例代码如下)并发现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()
答案 0 :(得分:3)
您需要关闭所有描述符访问权限,以便ssh知道它永远不会再获取任何数据。换句话说,在描述符0到2上调用os.close
。实际上,您需要 open ,因此最好打开os.devnull
和{{ 1}}结果描述符超过0,1和2(对于真正健壮的软件,确保os.dup2
不会返回值os.open
,当然 - 如果是,那么&#39} ;好吧,只需将其保留在原位,然后重复其余部分。)
(你还需要通常的双叉技巧,抛弃会话ID等可能是明智的。在一些Unix派生系统中,有一个名为0 <= fd <= 2
的库例程,可能在libc或libutil,它可以为你完成所有这些。一些细节不可避免地依赖于操作系统,例如放弃控制终端的方式。但是,你链接的Python特定答案中缺少的主要内容是替换stdin / stdout / stderr descriptors。)