使用 bash 进行服务闲置检查

2019-08-10  本文已影响0人  虚胖一场

本文链接个人站 | 简书 | CSDN
版权声明:除特别声明外,本博客文章均采用 BY-NC-SA 许可协议。转载请注明出处。

重启服务之前往往需要检查一下是否还有未处理完的请求。此时可以使用 ss 命令查看端口是否还有 TCP 连接。例如:

pi@raspberrypi:~ $ ss -nt state established src 192.168.1.26:8888
Recv-Q Send-Q Local Address:Port               Peer Address:Port              
0      0      192.168.1.26:8888               192.168.1.25:50390

我们可以统计这条命令输出的行数,若小于 2,则说明服务已经处于闲置状态。脚本如下:

#!/bin/bash

# 获取本机 IP
host=$(ifconfig -a | grep inet | grep -v 127.0.0.1 | grep -v inet6 | awk '{print $2}' | tr -d "addr:")
# 超时时间
timeout=3600

check(){
  port="$1"
  begin=$(date +'%s')
  while true
  do
    current=$(date +'%s')
    duration=$(($current-$begin))
    if [[ $duration -gt $timeout ]]; then
      # 超时退出
      result="TIMEOUT"
      code=1
      break
    count=$(ss -nt state established src $host:$port | wc -l)
    if [[ $count -lt 2 ]]; then
      # 闲置退出
      result="IDLE"
      code=0
      break
    else
      sleep 2
    fi
  done
  echo "the result is $result"
  return $code
}

if [[ $# -ne 1 ]]; then
  echo "Usage: $0 [port]"
  exit 1
else
  check "$1"
  exit $?
fi

如果 ss 命令发生错误怎么办?为了进一步完善脚本,我们需要加入异常处理机制。bash 中没有 try...catch.. 之类的语法,那么该如何捕获异常呢?下面介绍两个特殊的写法:

利用上面这两个特性,我们引入异常处理,把脚本改写成:

#!/bin/bash

set -o pipefail

# 获取本机 IP
host=$(ifconfig -a | grep inet | grep -v 127.0.0.1 | grep -v inet6 | awk '{print $2}' | tr -d "addr:")
# 超时时间
timeout=3600

check(){
  port="$1"
  begin=$(date +'%s')
  while true
  do
    current=$(date +'%s')
    duration=$(($current-$begin))
    if [[ $duration -gt $timeout ]]; then
      # 超时退出
      result="TIMEOUT"
      code=1
      break
    {
      count=$(ss -nt state established src $host:$port | wc -l) &&
      if [[ $count -lt 2 ]]; then
        # 闲置退出
        result="IDLE"
        code=0
        break
      else
        sleep 2
      fi
    }||{
      # 异常退出
      result="ERROR"
      code=1
      break
    }
  done
  echo "the result is $result"
  return $code
}

if [[ $# -ne 1 ]]; then
  echo "Usage: $0 [port]"
  exit 1
else
  check "$1"
  exit $?
fi

ss -nt state established src $host:$port | wc -l 利用了管道,而默认情况下,前面的 ss 命令出错并不会影响后面的 wc 命令的执行。为了捕获管道中的错误,我们在脚本开头添加了 set -o pipefail

现在我们的脚本可以检测一个服务实例是否闲置。如果我们需要同时检查多个实例该怎么办?如果可以并行地执行我们的 check 函数就好了。我们知道,在一条命令后面加上 &,就可以将它放到子 shell 中执行,达到多线程的效果。进一步地,我们可以用 wait 命令实现多线程同步。基于此,我们给出可以同时检查多个实例的 check_all 函数:

check_all(){
  ports="$#"
  anyfailed=0
  for port in $ports
  do
    check $port &
  done
  for pid in $(jobs -p)
  do
    wait $pid
    if [[ $? -ne 0 ]]; then
      anyfailed=1
    fi
  done
  return $anyfailed
}
上一篇下一篇

猜你喜欢

热点阅读