Shell脚本如何实现重试退避策略

wen 实用脚本 15

本文目录导读:

Shell脚本如何实现重试退避策略

  1. 指数退避(Exponential Backoff)
  2. 带随机抖动的指数退避
  3. 固定间隔重试
  4. 高级版本:支持错误处理和日志
  5. 使用 curl 的重试示例
  6. 实际使用示例
  7. 推荐的退避策略

Shell脚本实现重试退避策略有多种方式,以下是几种常见实现:

指数退避(Exponential Backoff)

#!/bin/bash
function retry_command() {
    local max_attempts=${1:-5}
    local initial_delay=${2:-1}
    local backoff_factor=${3:-2}
    local max_delay=${4:-60}
    local attempt=1
    local delay=$initial_delay
    while [ $attempt -le $max_attempts ]; do
        echo "尝试 $attempt/$max_attempts..."
        if "$@${@:5}" 2>/dev/null; then
            echo "成功执行"
            return 0
        fi
        echo "失败,等待 ${delay}秒后重试..."
        sleep $delay
        # 计算下一次延迟
        delay=$((delay * backoff_factor))
        if [ $delay -gt $max_delay ]; then
            delay=$max_delay
        fi
        ((attempt++))
    done
    echo "所有重试都失败"
    return 1
}
# 使用示例
retry_command 5 1 2 30 "your_command_here"

带随机抖动的指数退避

#!/bin/bash
function retry_with_jitter() {
    local max_attempts=${1:-5}
    local base_delay=${2:-2}
    local backoff_factor=${3:-2}
    local max_delay=${4:-120}
    local attempt=1
    local delay=$base_delay
    while [ $attempt -le $max_attempts ]; do
        echo "尝试 $attempt/$max_attempts..."
        # 执行命令
        if eval "${@:5}"; then
            echo "成功执行"
            return 0
        fi
        echo "失败,等待 ${delay}秒后重试..."
        # 添加随机抖动
        local jitter=$((RANDOM % 5 + 1))
        sleep $((delay + jitter))
        # 计算下一次延迟
        delay=$((delay * backoff_factor))
        if [ $delay -gt $max_delay ]; then
            delay=$max_delay
        fi
        ((attempt++))
    done
    echo "所有重试都失败"
    return 1
}

固定间隔重试

#!/bin/bash
function retry_fixed_interval() {
    local max_attempts=${1:-3}
    local interval=${2:-5}
    local attempt=1
    while [ $attempt -le $max_attempts ]; do
        echo "尝试 $attempt/$max_attempts..."
        if "$@${@:3}"; then
            echo "成功"
            return 0
        fi
        if [ $attempt -lt $max_attempts ]; then
            echo "失败,${interval}秒后重试..."
            sleep $interval
        fi
        ((attempt++))
    done
    echo "所有重试失败"
    return 1
}

高级版本:支持错误处理和日志

#!/bin/bash
function advanced_retry() {
    # 配置参数
    local max_attempts=5
    local initial_delay=1
    local max_delay=60
    local backoff_factor=2
    local retryable_exit_codes=(1 2 3)  # 可重试的错误码
    local attempt=1
    local delay=$initial_delay
    local logfile="/var/log/retry.log"
    while [ $attempt -le $max_attempts ]; do
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 尝试 $attempt/$max_attempts" | tee -a $logfile
        # 执行命令并捕获输出和退出码
        output=$("$@" 2>&1)
        exit_code=$?
        if [ $exit_code -eq 0 ]; then
            echo "[$(date +'%Y-%m-%d %H:%M:%S')] 成功执行" | tee -a $logfile
            return 0
        fi
        # 检查退出码是否可重试
        local retryable=false
        for code in "${retryable_exit_codes[@]}"; do
            if [ $exit_code -eq $code ]; then
                retryable=true
                break
            fi
        done
        if [ "$retryable" = false ] && [ $attempt -lt $max_attempts ]; then
            echo "[$(date +'%Y-%m-%d %H:%M:%S')] 不可重试的错误码: $exit_code" | tee -a $logfile
            return $exit_code
        fi
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 失败 (退出码: $exit_code)" | tee -a $logfile
        if [ $attempt -lt $max_attempts ]; then
            echo "等待 ${delay}秒后重试..." | tee -a $logfile
            sleep $delay
            # 指数退避
            delay=$((delay * backoff_factor))
            [ $delay -gt $max_delay ] && delay=$max_delay
        fi
        ((attempt++))
    done
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 所有重试都失败" | tee -a $logfile
    return 1
}

使用 curl 的重试示例

#!/bin/bash
# curl 内置的重试功能
function curl_with_retry() {
    local url=$1
    local max_retries=${2:-3}
    curl \
        --retry $max_retries \
        --retry-delay 5 \
        --retry-max-time 60 \
        --retry-connrefused \
        -s \
        -o /dev/null \
        -w "%{http_code}" \
        "$url"
}
# 使用示例
curl_with_retry "https://api.example.com" 5

实际使用示例

#!/bin/bash
source ./retry_functions.sh
# 示例1: 重试文件下载
retry_with_jitter 5 2 2 30 "wget -q https://example.com/largefile.zip"
# 示例2: 重试数据库连接
retry_command 3 5 1 30 "mysql -h host -u user -ppassword -e 'SELECT 1'"
# 示例3: 重试 API 调用
advanced_retry "curl -X POST https://api.example.com/data"
# 示例4: 重试直到成功或超时
TIMEOUT=300
START_TIME=$(date +%s)
while true; do
    if your_command; then
        break
    fi
    CURRENT_TIME=$(date +%s)
    ELAPSED=$((CURRENT_TIME - START_TIME))
    if [ $ELAPSED -ge $TIMEOUT ]; then
        echo "超时"
        exit 1
    fi
    sleep 5
done

推荐的退避策略

  1. 指数退避:适用于瞬时故障
  2. 指数退避+随机抖动:避免惊群效应
  3. 固定间隔:简单可预测,适用于非临界操作
  4. 线性递增:适用于需要逐渐增加间隔的场景

选择哪种策略取决于你的具体需求和失败原因。

抱歉,评论功能暂时关闭!