mirror of
https://git.bjxgj.com/xgj/xgj-actions.git
synced 2025-10-14 06:33:37 +08:00
378 lines
12 KiB
YAML
378 lines
12 KiB
YAML
# 错误处理和恢复示例
|
|
# 演示如何使用状态缓存进行错误处理、状态恢复和重试逻辑
|
|
|
|
name: Cache State - 错误处理示例
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
simulate_error:
|
|
description: '模拟错误类型'
|
|
required: false
|
|
default: 'none'
|
|
type: choice
|
|
options:
|
|
- none
|
|
- network_error
|
|
- build_failure
|
|
- deployment_error
|
|
recovery_mode:
|
|
description: '恢复模式'
|
|
required: false
|
|
default: 'auto'
|
|
type: choice
|
|
options:
|
|
- auto
|
|
- manual
|
|
- skip
|
|
|
|
jobs:
|
|
initialize-operation:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
operation-id: ${{ steps.operation-setup.outputs.operation-id }}
|
|
should-continue: ${{ steps.check-previous.outputs.should-continue }}
|
|
steps:
|
|
- name: 检出代码
|
|
uses: actions/checkout@v4
|
|
|
|
- name: 设置操作ID
|
|
id: operation-setup
|
|
run: |
|
|
OPERATION_ID="op-$(date +%s)-${{ github.run_number }}"
|
|
echo "operation-id=${OPERATION_ID}" >> $GITHUB_OUTPUT
|
|
echo "🆔 操作ID: ${OPERATION_ID}"
|
|
|
|
- name: 检查上次操作状态
|
|
id: last-operation
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'last-operation-status'
|
|
default-value: 'none'
|
|
action: 'get'
|
|
cache-prefix: 'operation'
|
|
|
|
- name: 检查是否有失败的操作需要恢复
|
|
id: check-previous
|
|
run: |
|
|
LAST_STATUS="${{ steps.last-operation.outputs.state-value }}"
|
|
RECOVERY_MODE="${{ github.event.inputs.recovery_mode }}"
|
|
|
|
echo "🔍 检查上次操作状态: ${LAST_STATUS}"
|
|
echo "🔧 恢复模式: ${RECOVERY_MODE}"
|
|
|
|
if [[ "${LAST_STATUS}" == "failed" || "${LAST_STATUS}" == "partial" ]]; then
|
|
echo "⚠️ 检测到失败的操作需要处理"
|
|
|
|
case "${RECOVERY_MODE}" in
|
|
"auto")
|
|
echo "🔄 自动恢复模式,将继续操作"
|
|
echo "should-continue=true" >> $GITHUB_OUTPUT
|
|
;;
|
|
"manual")
|
|
echo "✋ 手动恢复模式,需要人工干预"
|
|
echo "should-continue=false" >> $GITHUB_OUTPUT
|
|
exit 1
|
|
;;
|
|
"skip")
|
|
echo "⏭️ 跳过恢复,开始新操作"
|
|
echo "should-continue=true" >> $GITHUB_OUTPUT
|
|
;;
|
|
esac
|
|
else
|
|
echo "✅ 没有失败的操作,正常继续"
|
|
echo "should-continue=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: 记录操作开始
|
|
if: steps.check-previous.outputs.should-continue == 'true'
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'current-operation-id'
|
|
state-value: ${{ steps.operation-setup.outputs.operation-id }}
|
|
action: 'set'
|
|
cache-prefix: 'operation'
|
|
|
|
- name: 记录操作状态为进行中
|
|
if: steps.check-previous.outputs.should-continue == 'true'
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'last-operation-status'
|
|
state-value: 'running'
|
|
action: 'set'
|
|
cache-prefix: 'operation'
|
|
|
|
build-with-retry:
|
|
needs: initialize-operation
|
|
if: needs.initialize-operation.outputs.should-continue == 'true'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: 检出代码
|
|
uses: actions/checkout@v4
|
|
|
|
- name: 检查构建重试状态
|
|
id: retry-status
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'build-retry-count-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
default-value: '0'
|
|
action: 'get'
|
|
cache-prefix: 'retry'
|
|
|
|
- name: 准备构建重试
|
|
id: prepare-retry
|
|
run: |
|
|
CURRENT_RETRY=${{ steps.retry-status.outputs.state-value }}
|
|
MAX_RETRIES=3
|
|
|
|
echo "🔄 当前重试次数: ${CURRENT_RETRY}/${MAX_RETRIES}"
|
|
|
|
if [[ ${CURRENT_RETRY} -ge ${MAX_RETRIES} ]]; then
|
|
echo "❌ 已达到最大重试次数"
|
|
echo "can-retry=false" >> $GITHUB_OUTPUT
|
|
exit 1
|
|
else
|
|
echo "✅ 可以继续重试"
|
|
echo "can-retry=true" >> $GITHUB_OUTPUT
|
|
echo "next-retry=$((CURRENT_RETRY + 1))" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: 模拟构建过程
|
|
id: build
|
|
run: |
|
|
echo "🔨 开始构建过程..."
|
|
|
|
# 根据输入模拟不同类型的错误
|
|
case "${{ github.event.inputs.simulate_error }}" in
|
|
"build_failure")
|
|
echo "❌ 模拟构建失败"
|
|
exit 1
|
|
;;
|
|
"network_error")
|
|
echo "🌐 模拟网络错误"
|
|
sleep 2
|
|
exit 1
|
|
;;
|
|
*)
|
|
echo "✅ 构建成功"
|
|
;;
|
|
esac
|
|
|
|
- name: 更新重试计数(失败时)
|
|
if: failure()
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'build-retry-count-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
state-value: ${{ steps.prepare-retry.outputs.next-retry }}
|
|
action: 'set'
|
|
cache-prefix: 'retry'
|
|
|
|
- name: 记录构建失败状态
|
|
if: failure()
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'build-status-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
state-value: 'failed'
|
|
action: 'set'
|
|
cache-prefix: 'build'
|
|
|
|
- name: 记录构建失败时间
|
|
if: failure()
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'build-failure-time-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
state-value: ${{ github.event.head_commit.timestamp }}
|
|
action: 'set'
|
|
cache-prefix: 'build'
|
|
|
|
- name: 清理重试计数(成功时)
|
|
if: success()
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'build-retry-count-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
state-value: ''
|
|
action: 'set'
|
|
cache-prefix: 'retry'
|
|
|
|
- name: 记录构建成功状态
|
|
if: success()
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'build-status-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
state-value: 'success'
|
|
action: 'set'
|
|
cache-prefix: 'build'
|
|
|
|
deploy-with-rollback:
|
|
needs: [initialize-operation, build-with-retry]
|
|
if: success()
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: 检出代码
|
|
uses: actions/checkout@v4
|
|
|
|
- name: 获取上次成功的部署版本
|
|
id: last-deploy
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'last-successful-deployment'
|
|
default-value: 'v1.0.0'
|
|
action: 'get'
|
|
cache-prefix: 'deploy'
|
|
|
|
- name: 备份当前部署状态
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'deployment-backup-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
state-value: ${{ steps.last-deploy.outputs.state-value }}
|
|
action: 'set'
|
|
cache-prefix: 'backup'
|
|
|
|
- name: 模拟部署过程
|
|
id: deploy
|
|
run: |
|
|
echo "🚀 开始部署..."
|
|
echo "📦 部署版本: ${{ github.sha }}"
|
|
echo "🔙 备份版本: ${{ steps.last-deploy.outputs.state-value }}"
|
|
|
|
# 模拟部署错误
|
|
if [[ "${{ github.event.inputs.simulate_error }}" == "deployment_error" ]]; then
|
|
echo "❌ 模拟部署失败"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ 部署成功"
|
|
|
|
- name: 记录部署成功
|
|
if: success()
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'last-successful-deployment'
|
|
state-value: ${{ github.sha }}
|
|
action: 'set'
|
|
cache-prefix: 'deploy'
|
|
|
|
- name: 清理备份(成功时)
|
|
if: success()
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'deployment-backup-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
state-value: ''
|
|
action: 'set'
|
|
cache-prefix: 'backup'
|
|
|
|
- name: 执行回滚(失败时)
|
|
if: failure()
|
|
run: |
|
|
echo "🔄 部署失败,开始回滚..."
|
|
ROLLBACK_VERSION="${{ steps.last-deploy.outputs.state-value }}"
|
|
echo "回滚到版本: ${ROLLBACK_VERSION}"
|
|
|
|
# 这里执行实际的回滚操作
|
|
echo "✅ 回滚完成"
|
|
|
|
- name: 记录回滚状态
|
|
if: failure()
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'rollback-executed-${{ needs.initialize-operation.outputs.operation-id }}'
|
|
state-value: 'true'
|
|
action: 'set'
|
|
cache-prefix: 'rollback'
|
|
|
|
finalize-operation:
|
|
needs: [initialize-operation, build-with-retry, deploy-with-rollback]
|
|
if: always() && needs.initialize-operation.outputs.should-continue == 'true'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: 检出代码
|
|
uses: actions/checkout@v4
|
|
|
|
- name: 确定最终操作状态
|
|
id: final-status
|
|
run: |
|
|
BUILD_RESULT="${{ needs.build-with-retry.result }}"
|
|
DEPLOY_RESULT="${{ needs.deploy-with-rollback.result }}"
|
|
|
|
echo "🔍 构建结果: ${BUILD_RESULT}"
|
|
echo "🔍 部署结果: ${DEPLOY_RESULT}"
|
|
|
|
if [[ "${BUILD_RESULT}" == "success" && "${DEPLOY_RESULT}" == "success" ]]; then
|
|
FINAL_STATUS="success"
|
|
elif [[ "${BUILD_RESULT}" == "failure" ]]; then
|
|
FINAL_STATUS="build_failed"
|
|
elif [[ "${DEPLOY_RESULT}" == "failure" ]]; then
|
|
FINAL_STATUS="deploy_failed"
|
|
elif [[ "${BUILD_RESULT}" == "success" && "${DEPLOY_RESULT}" == "skipped" ]]; then
|
|
FINAL_STATUS="partial"
|
|
else
|
|
FINAL_STATUS="unknown"
|
|
fi
|
|
|
|
echo "final-status=${FINAL_STATUS}" >> $GITHUB_OUTPUT
|
|
echo "🏁 最终状态: ${FINAL_STATUS}"
|
|
|
|
- name: 记录最终操作状态
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'last-operation-status'
|
|
state-value: ${{ steps.final-status.outputs.final-status }}
|
|
action: 'set'
|
|
cache-prefix: 'operation'
|
|
|
|
- name: 记录操作完成时间
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'last-operation-time'
|
|
state-value: ${{ github.event.head_commit.timestamp }}
|
|
action: 'set'
|
|
cache-prefix: 'operation'
|
|
|
|
- name: 生成错误处理报告
|
|
run: |
|
|
echo "📋 错误处理和恢复报告"
|
|
echo "========================"
|
|
echo "操作ID: ${{ needs.initialize-operation.outputs.operation-id }}"
|
|
echo "最终状态: ${{ steps.final-status.outputs.final-status }}"
|
|
echo "模拟错误类型: ${{ github.event.inputs.simulate_error }}"
|
|
echo "恢复模式: ${{ github.event.inputs.recovery_mode }}"
|
|
echo ""
|
|
|
|
case "${{ steps.final-status.outputs.final-status }}" in
|
|
"success")
|
|
echo "✅ 操作成功完成"
|
|
;;
|
|
"build_failed")
|
|
echo "❌ 构建失败,请检查构建日志"
|
|
;;
|
|
"deploy_failed")
|
|
echo "❌ 部署失败,已执行回滚"
|
|
;;
|
|
"partial")
|
|
echo "⚠️ 部分完成,可能需要手动干预"
|
|
;;
|
|
*)
|
|
echo "❓ 状态未知,需要进一步调查"
|
|
;;
|
|
esac
|
|
|
|
cleanup-expired-states:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: 检出代码
|
|
uses: actions/checkout@v4
|
|
|
|
- name: 清理过期的重试状态
|
|
run: |
|
|
echo "🧹 清理过期的状态信息..."
|
|
# 这里可以实现清理逻辑
|
|
# 例如,清理超过一定时间的重试计数、备份等临时状态
|
|
|
|
- name: 清理示例 - 重置错误计数
|
|
uses: .actions/xgj/cache-state@v1
|
|
with:
|
|
state-key: 'error-count-global'
|
|
state-value: '0'
|
|
action: 'set'
|
|
cache-prefix: 'cleanup'
|