# 错误处理和恢复示例 # 演示如何使用状态缓存进行错误处理、状态恢复和重试逻辑 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'