Files
actions/retry/action.yaml
T
2024-11-10 16:43:54 +01:00

138 lines
4.6 KiB
YAML

# Ultralytics Actions 🚀, AGPL-3.0 License https://ultralytics.com/license
#
# Example usage:
#
# Basic usage (will retry failed step 3 times):
# steps:
# - uses: ultralytics/actions/retry@main
# with:
# run: python train.py
#
# Advanced usage:
# steps:
# - uses: ultralytics/actions/retry@main
# with:
# run: |
# python setup.py install
# pytest tests/
# retries: 2 # Retry twice after initial attempt (3 total runs)
# timeout_minutes: 30 # Each attempt times out after 30 minutes
# retry_delay_seconds: 60 # Wait 60 seconds between retries
# shell: bash # Use python or bash shell
name: "Step-Level Retry"
description: "Retries a step while preserving its full context"
inputs:
timeout_minutes:
description: "Maximum time in minutes for each attempt"
required: false
default: "60"
retries:
description: "Number of retry attempts after initial run"
required: false
default: "3"
retry_delay_seconds:
description: "Delay between retries in seconds"
required: false
default: "30"
run:
description: "Command to run"
required: true
shell:
description: "Shell to use (bash or python)"
required: false
default: "bash"
runs:
using: "composite"
steps:
- name: Execute with retry (Python)
if: inputs.shell == 'python'
shell: python
env: ${{ env }}
run: |
import time
start_time = time.time()
timeout_seconds = ${{ inputs.timeout_minutes }} * 60
attempt = 1
max_attempts = 1 + ${{ inputs.retries }} # Initial run + retries
while True:
if attempt > 1:
print(f"::group::Retry {attempt-1} of ${{ inputs.retries }}")
if (time.time() - start_time) > timeout_seconds:
print(f"::error::Step timed out after ${{ inputs.timeout_minutes }} minutes")
exit(1)
try:
${{ inputs.run }}
if attempt > 1:
print("::endgroup::")
exit(0)
except Exception as e:
if attempt > 1:
print(f"Retry {attempt-1} failed with error: {str(e)}")
print("::endgroup::")
else:
print(f"Initial attempt failed with error: {str(e)}")
if attempt >= max_attempts:
print(f"::error::Step failed after initial attempt and {attempt-1} retries")
exit(1)
print(f"Retrying in ${{ inputs.retry_delay_seconds }} seconds...")
time.sleep(${{ inputs.retry_delay_seconds }})
attempt += 1
- name: Execute with retry (Bash)
if: inputs.shell != 'python'
shell: bash
env: ${{ env }}
run: |
function retry_command {
local start_time=$(date +%s)
local timeout_seconds=$(( ${{ inputs.timeout_minutes }} * 60 ))
local attempt=1
local max_attempts=$(( 1 + ${{ inputs.retries }} )) # Initial run + retries
while true; do
if [ $attempt -gt 1 ]; then
echo "::group::Retry $((attempt-1)) of ${{ inputs.retries }}"
fi
local current_time=$(date +%s)
if [ $((current_time - start_time)) -gt $timeout_seconds ]; then
echo "::error::Step timed out after ${{ inputs.timeout_minutes }} minutes"
return 1
fi
set +e
${{ inputs.run }}
local exit_code=$?
set -e
if [ $exit_code -eq 0 ]; then
[ $attempt -gt 1 ] && echo "::endgroup::"
return 0
fi
if [ $attempt -gt 1 ]; then
echo "Retry $((attempt-1)) failed with exit code $exit_code"
echo "::endgroup::"
else
echo "Initial attempt failed with exit code $exit_code"
fi
if [ $attempt -ge $max_attempts ]; then
echo "::error::Step failed after initial attempt and $((attempt-1)) retries"
return $exit_code
fi
echo "Retrying in ${{ inputs.retry_delay_seconds }} seconds..."
sleep ${{ inputs.retry_delay_seconds }}
attempt=$((attempt + 1))
done
}
retry_command