下面是我的代码片段。
idql -n $REPOSITORY_NAME.$cs -Udmadmin -P"" -R$DM_SCRIPTS/test.api > /dev/null 2>&1
if [ $? != 0 ]; then
echo " \c"
echo "ERROR: Cannot connect to: $REPOSITORY_NAME.$cs on $HOST"
else
echo " Successfully connected to: $REPOSITORY_NAME.$cs"
fi
这是我们用于监控服务的主要逻辑。但我们经常看到我们的服务被挂起,因此上面代码片段的第一行被挂起,之后就不再继续了。因此,我们无法捕获这种“服务挂起”的情况。
最重要的是,我们必须保留对现有条件的检查(在 if-else 条件语句中指定),此外,我们还必须检查“挂起”状态。如果命令idql
耗时超过 5 秒,我们可以假设它已挂起。
答案1
我想你想要timeout
命令,它是您系统的一部分coreutils
并且应该在您的系统上可用
要在 5 秒后终止该命令,请更改为:
timeout 5 iqdl -n $REPOSITORY_NAME.$cs ...
如果你没有coreutils
,您可以从这里下载、构建并安装它:http://www.gnu.org/software/coreutils/
也可以看看:https://stackoverflow.com/questions/687948/timeout-a-command-in-bash-without-unnecessary-delay
答案2
我能够修改解决方案http://h30499.www3.hp.com/t5/System-Administration/Capturing-hung-command-in-a-script/td-p/5662103以满足我的要求。
我测试过,这对我来说是完美的。我感谢你的所有帮助。
#!/bin/ksh
WAITTIME=5
# run the idql command in the background, discarding any output
idql -n $REPOSITORY_NAME -Udmadmin -P"" -R"$DM_SCRIPTS/test.api" >/dev/null 2>&1 &
IDQL_PID=$!
# set up a timeout that will kill the idql command when
# $WAITTIME seconds has passed, unless it has completed before that.
(sleep $WAITTIME; kill $IDQL_PID 2>/dev/null) &
TIMEOUT_PID=$!
# wait for the idql command to either complete or get killed; read its return status
wait $IDQL_PID
RESULT=$?
# if the timeout is still running, stop it (ignore any errors)
kill $TIMEOUT_PID 2>/dev/null
# read the return status of the timeout process (we don't need it
# but running the wait function prevents it from remaining as a
# zombie process)
wait $TIMEOUT_PID
if [ $RESULT -eq 1 ];then
echo "something is wrong with $REPOSITORY_NAME, It seems to be down. Result - $RESULT"
elif [ $RESULT -eq 143 ];then
echo "Attention!!! ***$REPOSITORY_NAME seems to be HUNG*** Result - $RESULT"
else
echo "$REPOSITORY_NAME seems to be OK. Result - $RESULT"
fi
答案3
如果idql
在挂起时在循环中使用 CPU 时间,则可以对其总 CPU 时间进行限制:
( ulimit -t 5;
idql -n $REPOSITORY_NAME.$cs -Udmadmin -P"" -R$DM_SCRIPTS/test.api > /dev/null 2>&1 )
如果idql
由于其他原因(例如死锁)而阻塞,则必须按照挂钟时间进行超时。这是一个解决方案,由于史蒂芬·希门尼斯,稍作修改以获取命令的退出状态idql
。
ret=$(sh -ic '{ { idql -n "$REPOSITORY_NAME.$cs" -Udmadmin -P"" -R"$DM_SCRIPTS/test.api" > /dev/null 2>&1;
echo $? >&3;
kill 0; } |
{ sleep 5; kill 0; } }' </dev/null 3>&1 2>/dev/null)
if [ -z "$ret" ]; then
echo "timed out"
elif [ "$ret" -ne 0 ]; then
echo "error $ret"
else
echo "ok"
fi
解释:
- 启动交互式 shell (
sh -i
)。由于这个 shell 是交互式的,所以它有自己的进程组。 - 子 shell 运行通过管道连接在一起的两个命令。这允许两个命令在同一进程组内并行执行。
- 这两个命令都以 结尾
kill 0
,这会杀死进程组内的所有命令。无论哪个命令先结束(idql
或sleep
),都会杀死另一个命令。 idql
打印文件描述符 3的返回状态,这样它就不会通过管道。文件描述符 3 被重定向到外壳中的文件描述符 1,以便命令替换捕获该 fd 上的输出。- 重定向交互式 shell 的标准错误,以免
/dev/null
从内 shell 中显示任何“已终止”消息。如果您想查看 的错误输出idql
,则需要重定向它(idql 2>&4
而不是idql 2>/dev/null
, 并在of4>&2
之前添加)。2>/dev/null
sh -i
- 重定向交互式 shell 的标准输入,以便在您按+
/dev/null
时它不会最终从终端读取命令。CtrlC