Perl 中的 Rsync system() 执行随机失败并出现协议错误
Rsync system() execution in Perl fails randomly with protocol error
我们通常在 (Mod)Perl(和 PHP)中调用 rsync
,并没有 运行 遇到太多问题,但我们 运行 在 运行 执行命令时出现偶尔的协议错误,而在后续请求 运行 时执行正常。有趣的是,即使我在代码中重试,对于同一个http请求,它每次都会失败,但是如果你发出另一个http请求,它很可能会成功。
代码如下所示:
$cmd = sprintf('rsync -auvvv --rsync-path="rsync --log-file=/tmp/ui-rsync.log" %s %s', "$fromDir/$fromBase/", "$path/$toBase/");
$exitCode = system($cmd);
--rsync-path 参数后来被添加到那里用于调试。这是没有帮助的。无论哪种方式都失败了。
错误如下所示:
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]
或者像这样:
unexpected tag 93 [receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(1134) [receiver=3.0.6]
rsync: connection unexpectedly closed (9 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]
我调试了实际生成的命令,我可以 运行 手动执行它们。
http 用户可以 运行 命令正常。
同样,编程重试 永远不会 有效,但手动重试(点击触发它的同一 http 端点)几乎总是有效。
感谢任何帮助,因为这让我们发疯了......很长一段时间,尝试了许多修复。
如果这是真实的 heisenbug,您可以重试 rsync 大概三次,中间休息一下:
for my $n (1..3){
my $exitCode = system($cmd);
my_log_sub("SUCCESS: rsync succeded on try $n") + last if $exitCode==0;
my_log_sub("ERROR: rsync $n of 3 failed: $cmd $! $?");
sleep(1) if $n<3;
}
你检查过你的本地和远程日志了吗?失败后立即尝试 sudo ls -rtl /var/log/
或 sudo ls -rtl /var/log/httpd/
并在重试时 tail -f /var/log/one_of_the_newest_logs
。
您检查过远程磁盘是否已满或目录是否存在?防火墙问题?远程和本地 rsync 或 ssh 版本(非常)不同? (虽然我想这应该会显示更清晰的错误信息)
解决方案是将 system() 更改为反引号。严重地。我不知道为什么会这样。
字面上的变化是这样的:
# BAD:
$exitCode = system($cmd);
# GOOD:
`$cmd`;
如果我不得不猜测,我会说 shell 的初始化方式存在一些细微差别,可能是某些环境变量或内存位置未正确清理。不过我真的不知道。
我们通常在 (Mod)Perl(和 PHP)中调用 rsync
,并没有 运行 遇到太多问题,但我们 运行 在 运行 执行命令时出现偶尔的协议错误,而在后续请求 运行 时执行正常。有趣的是,即使我在代码中重试,对于同一个http请求,它每次都会失败,但是如果你发出另一个http请求,它很可能会成功。
代码如下所示:
$cmd = sprintf('rsync -auvvv --rsync-path="rsync --log-file=/tmp/ui-rsync.log" %s %s', "$fromDir/$fromBase/", "$path/$toBase/");
$exitCode = system($cmd);
--rsync-path 参数后来被添加到那里用于调试。这是没有帮助的。无论哪种方式都失败了。
错误如下所示:
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]
或者像这样:
unexpected tag 93 [receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(1134) [receiver=3.0.6]
rsync: connection unexpectedly closed (9 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]
我调试了实际生成的命令,我可以 运行 手动执行它们。
http 用户可以 运行 命令正常。
同样,编程重试 永远不会 有效,但手动重试(点击触发它的同一 http 端点)几乎总是有效。
感谢任何帮助,因为这让我们发疯了......很长一段时间,尝试了许多修复。
如果这是真实的 heisenbug,您可以重试 rsync 大概三次,中间休息一下:
for my $n (1..3){
my $exitCode = system($cmd);
my_log_sub("SUCCESS: rsync succeded on try $n") + last if $exitCode==0;
my_log_sub("ERROR: rsync $n of 3 failed: $cmd $! $?");
sleep(1) if $n<3;
}
你检查过你的本地和远程日志了吗?失败后立即尝试 sudo ls -rtl /var/log/
或 sudo ls -rtl /var/log/httpd/
并在重试时 tail -f /var/log/one_of_the_newest_logs
。
您检查过远程磁盘是否已满或目录是否存在?防火墙问题?远程和本地 rsync 或 ssh 版本(非常)不同? (虽然我想这应该会显示更清晰的错误信息)
解决方案是将 system() 更改为反引号。严重地。我不知道为什么会这样。
字面上的变化是这样的:
# BAD:
$exitCode = system($cmd);
# GOOD:
`$cmd`;
如果我不得不猜测,我会说 shell 的初始化方式存在一些细微差别,可能是某些环境变量或内存位置未正确清理。不过我真的不知道。