git进程在作为Python子进程运行时从不退出



背景

我正在编写一个Python程序来处理LFS错误消息,因为我在Bitbucket Server中有一些带有丢失LFS文件的repo。当您想找出repo中缺少哪些LFS文件时,运行git lfs fetch --all时的输出并不是很有用。这就是为什么我要为它制作一个工具。也许当我完成它后,它可以以某种形式贡献给git项目?

代码片段

import subprocess
def git_lfs_fetch(repo_dir) -> list:
timeout_sec = 120
try:
completed_process = subprocess.run(
["git", "lfs", "fetch", "--all"], check=False, cwd=repo_dir, 
capture_output=True, text=True, timeout=timeout_sec, shell=False)
return completed_process.stderr.split('n')
except subprocess.TimeoutExpired as ex:
print(f'ERROR Could not complete "{ex.cmd}" before timeout of {timeout_sec} s!')
print(ex.stderr)
return []

问题

有时,subprocess.run()方法永远不会返回,因为git-lfs进程永远不会退出。通常,在我的测试repos中运行git lfs fetch --all命令需要几秒钟才能完成。作为一种变通方法,我在subprocess.run()调用中添加了一个2分钟的timeout。我想我可以从异常中从stderr获得我感兴趣的输出,因为git-lfs已经完成了它应该做的一切。然而,这并没有帮助。Python似乎无法终止git子进程。我从文档中了解到,它向进程发送了一个SIGKILL,然后等待它退出。但它永远不会退出,即使设置了超时。

如果我从外部手动终止git-lfs进程,我会从ex.stderr打印出预期的输出,所以git-lfs看起来确实完成了,我的解决方法也应该完成。

环境

  • Windows 10, 64 bit
  • Python 3.10.7
  • git version 2.39.0.windows.2
    • 2.35.2.windows.1升级
  • git-lfs/3.3.0 (GitHub; windows amd64; go 1.19.3; git 77deabdf)
    • git-lfs/3.0.2 (GitHub; windows amd64; go 1.17.2)升级

修复我的解决方法

当我写这篇文章的时候,以一种典型的逃避方式,我有了一个想法。

由于Python无法强制终止git子进程,我尝试直接使用git-lfs,而不是让git调用它。这使得超时有效。

subprocess.run(["git-lfs", "fetch", "--all"], ...)

我在找什么

我正在寻找的解决方案是找出git-lfsgit不能正确终止的原因。更好的办法是解决这个问题。

我在Linux和Windows上(几年前)从Java和C#调用git时也遇到过类似的问题,即git命令实际上完成了它应该做的所有事情,但git进程从未终止。所以我认为;悬挂;这可能是git本身的一个问题。我真的很想知道为什么git-lfs进程不会退出。我不知道从哪里开始找。

更新

我使用了@CharlesDuffy的提示来尝试strace。我得到的一些输出并没有告诉我任何有用的东西。

在TaskManager中,我偶然发现有几个(7)ssh进程正在运行。在检查他们的命令行时,很明显他们与Git LFS有关,他们都在等待Bitbucket服务器的响应。向服务器发出的命令就是其中一个

  • ssh -p 7999 git@server-url "git-lfs-authenticate <path> download"
  • ssh -p 7999 git@server-url "git-lfs-transfer <path> download"

它们似乎是我看到问题并强行终止git-lfs进程时遗留下来的进程。

我用Git lfs 3.3.0将Git升级到最新版本2.39.0,然后重试。起初它似乎工作得更好,但后来我的git-lfs又卡住了。这次是从命令行运行,而不是从Python运行,任务管理器显示ssh.exe正在运行这个命令行,并且似乎被卡住了:

ssh -oControlMaster=Auto -oControlPath=C:UsersusernameAppdataLocalTempsock-3553225979sock-%C -p 7999 git@server-url "git-lfs-transfer <path> download"

使用Git Bash中的strace,我无法从挂起的ssh.exe进程中获得任何有用的信息,最终它在我试图再次连接strace时死亡。

由于服务器上的ssh守护进程存在于Bitbucket应用程序中,因此我认为下一步是为服务器端调试提供Atlassian支持。不过,我仍然缺乏一种可靠的方法来重现这个问题。

使用此方法

def git_lfs_fetch(repo_dir) -> list:
timeout_sec = 120
try:
completed_process = subprocess.run(
["git", "lfs", "fetch", "--all"], check=False, cwd=repo_dir, 
capture_output=True, text=True, timeout=timeout_sec, shell=False)
return completed_process.stderr.split('n')
except subprocess.TimeoutExpired as ex:
print(f'ERROR Could not complete "{ex.cmd}" before timeout of {timeout_sec} s!')
print(ex.stderr)
return []

相关内容

  • 没有找到相关文章

最新更新