Skip to content

Commit c334a33

Browse files
authored
ci: interrupt sudo command in runtime installation (#688)
## 📜 Description Fixed an issue when additional runtime installation can not be terminated after 10 minutes. ## 💡 Motivation and Context When using [nick-fields/retry](https://github.com/nick-fields/retry) and we interrupt sudo command then we are getting errors like this nick-fields/retry#114 or nick-fields/retry#124 To overcome this problem I decided to create own script for retrying a command. This PR delivers that. ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### CI - replace `nick-fields/retry` with own action; ## 🤔 How Has This Been Tested? Reduced timeout to 2 minutes and verified that action was repeated 3 times with 1 minute delay between attempts. ## 📸 Screenshots (if appropriate): <img width="1312" alt="image" src="https://github.com/user-attachments/assets/051aea2e-32d1-4878-bf8f-b6831948c7c2"> ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
1 parent 3eb78be commit c334a33

File tree

2 files changed

+109
-6
lines changed

2 files changed

+109
-6
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
name: "Retry sudo with Timeout"
2+
description: "Retries a sudo command with a specified timeout and max retries."
3+
author: "Kiryl Ziusko"
4+
inputs:
5+
command:
6+
description: "The command to run with retry and timeout"
7+
required: true
8+
timeout:
9+
description: "Timeout in seconds for each attempt"
10+
required: true
11+
default: 600
12+
max_retries:
13+
description: "Maximum number of retry attempts"
14+
required: true
15+
default: 3
16+
retry_interval:
17+
description: "Interval in seconds between retries"
18+
required: true
19+
default: 60
20+
runs:
21+
using: "composite"
22+
steps:
23+
- name: Execute command with retry and timeout
24+
shell: bash
25+
run: |
26+
# Parameters
27+
TIMEOUT=${{ inputs.timeout }}
28+
MAX_RETRIES=${{ inputs.max_retries }}
29+
RETRY_INTERVAL=${{ inputs.retry_interval }}
30+
COMMAND="${{ inputs.command }}"
31+
32+
RETRY_COUNT=0
33+
SUCCESS=0
34+
35+
run_with_timeout() {
36+
local command="$1"
37+
local start_time=$(date +%s)
38+
39+
# Run the command with sudo in the background
40+
sudo bash -c "$command" &
41+
local sudo_pid=$!
42+
43+
# Wait briefly to allow sudo to spawn its child process
44+
sleep 2
45+
46+
# Find the child process of sudo (actual command)
47+
local child_pid=$(pgrep -P $sudo_pid)
48+
49+
# Monitor the child process for timeout
50+
while sudo kill -0 $child_pid 2>/dev/null; do
51+
local current_time=$(date +%s)
52+
local elapsed_time=$((current_time - start_time))
53+
54+
# If timeout is exceeded, kill the child process
55+
if [[ $elapsed_time -ge $TIMEOUT ]]; then
56+
echo "Command timed out after ${TIMEOUT} seconds. Killing process $child_pid."
57+
sudo kill -9 $child_pid
58+
wait $child_pid 2>/dev/null
59+
return 124 # Return code 124 for timeout
60+
fi
61+
62+
# Sleep briefly to avoid a busy loop
63+
sleep 5
64+
done
65+
66+
# Wait for sudo command to finish and capture exit code
67+
wait $sudo_pid
68+
return $?
69+
}
70+
71+
# Start the retry loop
72+
while [[ $RETRY_COUNT -lt $MAX_RETRIES ]]; do
73+
echo "Attempt $((RETRY_COUNT + 1)) of $MAX_RETRIES for command..."
74+
75+
# Execute the command with targeted timeout
76+
COMMAND_EXIT_CODE=0
77+
run_with_timeout "$COMMAND" || COMMAND_EXIT_CODE=$?
78+
79+
# Check if the command succeeded
80+
if [[ $COMMAND_EXIT_CODE -eq 0 ]]; then
81+
SUCCESS=1
82+
echo "Command execution successful."
83+
break
84+
elif [[ $COMMAND_EXIT_CODE -eq 124 ]]; then
85+
echo "Command timed out after ${TIMEOUT} seconds."
86+
else
87+
echo "Command failed with exit code $COMMAND_EXIT_CODE"
88+
fi
89+
90+
echo "Retrying command in $RETRY_INTERVAL seconds..."
91+
sleep $RETRY_INTERVAL
92+
93+
# Increment the retry counter
94+
RETRY_COUNT=$((RETRY_COUNT + 1))
95+
done
96+
97+
# Exit with error if all attempts failed
98+
if [[ $SUCCESS -eq 0 ]]; then
99+
echo "All attempts to execute command failed."
100+
exit 1
101+
fi

.github/workflows/ios-e2e-test.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,17 @@ jobs:
122122
xcode-version: ${{ matrix.devices.xcode }}
123123
- name: Get Xcode version
124124
run: xcodebuild -version
125+
# needed for additional runtime installation
126+
- name: Install Xcodes
127+
run: brew tap robotsandpencils/made
125128
- name: Install additional iOS runtimes
126129
if: ${{ matrix.devices.runtime != '' && matrix.devices.runtime != null }}
127-
uses: nick-fields/retry@v3
130+
uses: ./.github/actions/retry-sudo-with-timeout
128131
with:
129-
timeout_minutes: 10
130-
max_attempts: 3
131-
command: |
132-
brew tap robotsandpencils/made
133-
sudo xcodes runtimes install --keep-archive 'iOS ${{ matrix.devices.runtime }}'
132+
command: "xcodes runtimes install --keep-archive 'iOS ${{ matrix.devices.runtime }}'"
133+
timeout: 600 # 10 minutes
134+
max_retries: 3
135+
retry_interval: 60
134136
- name: List all available simulators
135137
run: xcrun simctl list
136138
- name: Install AppleSimulatorUtils

0 commit comments

Comments
 (0)