| |
@@ -15,11 +15,16 @@
|
| |
import subprocess
|
| |
import sys
|
| |
import operator
|
| |
+ import time
|
| |
|
| |
# contains info about all rebuilds, add new rebuilds there and update rebuildid
|
| |
# here
|
| |
from massrebuildsinfo import MASSREBUILDS
|
| |
|
| |
+ # Configuration for retry logic
|
| |
+ MAX_RETRIES = 3 # Number of retries
|
| |
+ RETRY_DELAY = 5 # Delay in seconds between retries
|
| |
+
|
| |
# Set some variables
|
| |
# Some of these could arguably be passed in as args.
|
| |
rebuildid = 'f42'
|
| |
@@ -29,59 +34,65 @@
|
| |
workdir = os.path.expanduser('~/massbuild')
|
| |
enviro = os.environ
|
| |
|
| |
-
|
| |
- # Define functions
|
| |
-
|
| |
- # This function needs a dry-run like option
|
| |
+ # Retry logic wrapper function
|
| |
+ def retry(func, *args, retries=MAX_RETRIES, delay=RETRY_DELAY, **kwargs):
|
| |
+ """Retry logic wrapper function."""
|
| |
+ for attempt in range(retries):
|
| |
+ result = func(*args, **kwargs)
|
| |
+ if result == 0: # Success
|
| |
+ return 0
|
| |
+ print(f"Attempt {attempt + 1} failed. Retrying in {delay} seconds...")
|
| |
+ time.sleep(delay)
|
| |
+ print(f"All {retries} attempts failed.")
|
| |
+ return 1
|
| |
+
|
| |
+ # Updated buildmeoutput with retry logic
|
| |
def buildmeoutput(cmd, action, pkg, env, cwd=workdir):
|
| |
- """Simple function to run a command and return 0 for success, 1 for
|
| |
- failure. It also writes the taskID and name to a file and console.
|
| |
- cmd is the command and arguments, action is aname for the action (for
|
| |
- logging), pkg is the name of the packagebeing operated on, env is the
|
| |
- environment dict, and cwd is where the script should be executed from."""
|
| |
-
|
| |
- try:
|
| |
- output = subprocess.check_output(cmd, env=env, cwd=cwd).decode('utf-8').split()
|
| |
- with open(workdir+"/taskID_file", 'a') as task_file:
|
| |
- task_file.write('%s %s\n' % (pkg, output[2]))
|
| |
- sys.stdout.write(' Successful submission: %s taskID: %s\n' % (pkg, output[2]))
|
| |
- except subprocess.CalledProcessError as e:
|
| |
- sys.stderr.write('%s failed %s: %s\n' % (pkg, action, e))
|
| |
- return 1
|
| |
- return 0
|
| |
-
|
| |
- # This function needs a dry-run like option
|
| |
+ def attempt():
|
| |
+ try:
|
| |
+ output = subprocess.check_output(cmd, env=env, cwd=cwd).decode('utf-8').split()
|
| |
+ with open(workdir + "/taskID_file", 'a') as task_file:
|
| |
+ task_file.write('%s %s\n' % (pkg, output[2]))
|
| |
+ sys.stdout.write(' Successful submission: %s taskID: %s\n' % (pkg, output[2]))
|
| |
+ return 0
|
| |
+ except subprocess.CalledProcessError as e:
|
| |
+ sys.stderr.write('%s failed %s: %s\n' % (pkg, action, e))
|
| |
+ return 1
|
| |
+ return retry(attempt)
|
| |
+
|
| |
+ # Updated runme with retry logic
|
| |
def runme(cmd, action, pkg, env, cwd=workdir):
|
| |
- """Simple function to run a command and return 0 for success, 1 for
|
| |
- failure. cmd is a list of the command and arguments, action is a
|
| |
- name for the action (for logging), pkg is the name of the package
|
| |
- being operated on, env is the environment dict, and cwd is where
|
| |
- the script should be executed from."""
|
| |
-
|
| |
- try:
|
| |
- subprocess.check_call(cmd, env=env, cwd=cwd)
|
| |
- except subprocess.CalledProcessError as e:
|
| |
- sys.stderr.write('%s failed %s: %s\n' % (pkg, action, e))
|
| |
- return 1
|
| |
- return 0
|
| |
-
|
| |
- # This function needs a dry-run like option
|
| |
+ def attempt():
|
| |
+ try:
|
| |
+ subprocess.check_call(cmd, env=env, cwd=cwd)
|
| |
+ return 0
|
| |
+ except subprocess.CalledProcessError as e:
|
| |
+ sys.stderr.write('%s failed %s: %s\n' % (pkg, action, e))
|
| |
+ return 1
|
| |
+ return retry(attempt)
|
| |
+
|
| |
+ # Updated runmeoutput with retry logic
|
| |
def runmeoutput(cmd, action, pkg, env, cwd=workdir):
|
| |
- """Simple function to run a command and return output if successful.
|
| |
- cmd is a list of the command and arguments, action is a
|
| |
- name for the action (for logging), pkg is the name of the package
|
| |
- being operated on, env is the environment dict, and cwd is where
|
| |
- the script should be executed from. Returns 0 for failure"""
|
| |
-
|
| |
- try:
|
| |
- pid = subprocess.Popen(cmd, env=env, cwd=cwd,
|
| |
- stdout=subprocess.PIPE, encoding='utf8')
|
| |
- except BaseException as e:
|
| |
- sys.stderr.write('%s failed %s: %s\n' % (pkg, action, e))
|
| |
- return 0
|
| |
- result = pid.communicate()[0].rstrip('\n')
|
| |
- return result
|
| |
-
|
| |
+ def attempt():
|
| |
+ try:
|
| |
+ pid = subprocess.Popen(cmd, env=env, cwd=cwd,
|
| |
+ stdout=subprocess.PIPE, encoding='utf8')
|
| |
+ result = pid.communicate()[0].rstrip('\n')
|
| |
+ if pid.returncode == 0:
|
| |
+ return result
|
| |
+ else:
|
| |
+ return 0
|
| |
+ except BaseException as e:
|
| |
+ sys.stderr.write('%s failed %s: %s\n' % (pkg, action, e))
|
| |
+ return 0
|
| |
+ for attempt_number in range(MAX_RETRIES):
|
| |
+ result = attempt()
|
| |
+ if result:
|
| |
+ return result
|
| |
+ print(f"Attempt {attempt_number + 1} failed. Retrying in {RETRY_DELAY} seconds...")
|
| |
+ time.sleep(RETRY_DELAY)
|
| |
+ print(f"All {MAX_RETRIES} attempts failed for {pkg}.")
|
| |
+ return 0
|
| |
|
| |
# Environment for using releng credentials for pushing and building
|
| |
enviro['GIT_SSH'] = '/usr/local/bin/relengpush'
|
| |
@@ -110,7 +121,6 @@
|
| |
continue
|
| |
|
| |
# Query to see if a build has already been attempted
|
| |
- # this version requires newer koji:
|
| |
builds = kojisession.listBuilds(id, createdAfter=massrebuild['epoch'])
|
| |
newbuild = False
|
| |
# Check the builds to make sure they were for the target we care about
|
| |
@@ -119,7 +129,6 @@
|
| |
buildtarget = kojisession.getTaskInfo(build['task_id'],
|
| |
request=True)['request'][1]
|
| |
if buildtarget == massrebuild['target'] or buildtarget in massrebuild['targets']:
|
| |
- # We've already got an attempt made, skip.
|
| |
newbuild = True
|
| |
break
|
| |
except:
|
| |
@@ -142,7 +151,6 @@
|
| |
|
| |
# Check for a noautobuild file
|
| |
if os.path.exists(os.path.join(workdir, name, 'noautobuild')):
|
| |
- # Maintainer does not want us to auto build.
|
| |
print('Skipping %s due to opt-out' % name)
|
| |
continue
|
| |
|
| |
@@ -182,6 +190,7 @@
|
| |
if runme(commit, 'commit', name, enviro,
|
| |
cwd=os.path.join(workdir, name)):
|
| |
continue
|
| |
+
|
| |
# git push
|
| |
push = ['git', 'push', '--no-verify']
|
| |
print('Pushing changes for %s' % name)
|
| |
@@ -189,7 +198,6 @@
|
| |
cwd=os.path.join(workdir, name)):
|
| |
continue
|
| |
|
| |
-
|
| |
# get git url
|
| |
urlcmd = ['fedpkg', 'giturl']
|
| |
print('Getting git url for %s' % name)
|
| |
In the updated script, we introduced a retry mechanism to enhance the robustness of the build process.
The retry logic ensures that temporary infrastructure or network issues do not cause permanent failures.
Here’s a summary of what we added:
Retry Wrapper Function (
retry
):- A generic function to wrap other functions and enable retrying failed operations.
- Configurable retry count (
MAX_RETRIES
) and delay (RETRY_DELAY
) between attempts.Integration into Core Functions:
buildmeoutput
,runme
, andrunmeoutput
functions were modified to utilize the retry mechanism.Improved Logging and Error Handling:
Scalability:
Signed-off-by: Samyak Jain samyak.jn11@gmail.com