Repository: ClickHouse/ClickHouse
File: ci/praktika/utils.py (Python)

Code before:
                                break
                        if not should_retry:
                            print(
                                f"No retryable errors found, stopping retry attempts"
                            )
                            break
                    if should_retry and retry < retries - 1:
                        delay = min(2 ** (retry + 1), 60)
                        print(f"Retrying in {delay}s...")
                        time.sleep(delay)
            except Exception as e:
                if verbose:
                    if retries == 1:
                        print(
                            f"ERROR: command failed, exit code: {proc.returncode}"
                        )
                    else:
                        print(
                            f"Retry {retry+1}/{retries}: command failed, exit code: {proc.returncode}"
                        )
                if proc:
                    proc.kill()
                if strict and retry == retries - 1:
                    raise e
            if retry_sleep:
                time.sleep(retry_sleep)

        if strict and (not proc or proc.returncode != 0):
            err = "\n   ".join(err_output).strip()
            raise RuntimeError(
                f"command failed, exit code {proc.returncode},\nstderr:\n>>>\n{err}\n<<<"
            )

        return proc.returncode if proc else 1  # Return 1 if the process never started

    @classmethod
    def run_async(
        cls,
        command,
        stdin_str=None,
        verbose=False,
        suppress_output=False,
        **kwargs,
    ):
        if verbose:
            print(f"Run command in background [{command}]")
        proc = subprocess.Popen(
            command,
            shell=True,
            stderr=subprocess.STDOUT if not suppress_output else subprocess.DEVNULL,
            stdout=subprocess.PIPE if not suppress_output else subprocess.DEVNULL,

Review comment (bug):
The retry_sleep at this location causes double sleeping on failed retry attempts. When a command fails and needs to retry, both the exponential backoff sleep (line 420) and this retry_sleep (line 436) will execute, resulting in unnecessary delays. Additionally, this sleep executes even on the last failed attempt when no more retries will occur. The retry_sleep should either replace the exponential backoff mechanism or be removed entirely, as the exponential backoff on line 418-420 already provides appropriate delay between retries.
```suggestion

```

Code after:
                    err in err_line for err_line in err_output for err in retry_errors
                ):
                    if verbose:
                        print(f"No retryable errors found, stopping retries")
                    break

                if verbose:
                    matched = next(
                        (
                            err
                            for err in retry_errors
                            if any(err in line for line in err_output)
                        ),
                        "",
                    )
                    print(
                        f"Retryable error [{matched}] found, retry {retry+1}/{retries}"
                    )
            except Exception as e:
                if verbose:
                    if retries == 1:
                        print(f"ERROR: exception {e}")
                    else:
                        print(f"Retry {retry+1}/{retries}: exception {e}")
                        if retry == retries - 1:
                            print(f"ERROR: Final attempt failed, no more retries left.")
                if proc:
                    proc.kill()
                if retry == retries - 1:
                    if strict:
                        raise
                    else:
                        return 1  # Return non-zero for failure

        if verbose:
            print(
                f"ERROR: command failed after {retry+1}/{retries} attempt(s), exit code: {proc.returncode}"
            )

        if strict:
            err = "\n   ".join(err_output).strip()
            raise RuntimeError(
                f"command failed, exit code {proc.returncode},\nstderr:\n>>>\n{err}\n<<<"
            )

        return proc.returncode

    @classmethod
    def run_async(
        cls,
        command,