From 21c2d1fa84ed16d469d462789d317997715bdd37 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 00:15:17 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Optimize=20sequential=20gh?= =?UTF-8?q?=20CLI=20calls=20by=20parallelizing=20pr=20list=20checks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: xbmc4lyfe <273732874+xbmc4lyfe@users.noreply.github.com> --- .jules/bolt.md | 3 +++ ralph_loop/cli.py | 36 +++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..4b1e42f --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2026-05-27 - Parallelize gh CLI calls +**Learning:** Subprocess calls to the GitHub CLI ('gh') are a significant performance bottleneck. When checking states for multiple PRs sequentially, it creates an N+1 delay issue. +**Action:** Use concurrency (e.g., `concurrent.futures.ThreadPoolExecutor`) to eliminate sequential delays when making multiple independent subprocess CLI calls (e.g., checking PR open states). Ensure the original order is preserved by using `executor.map`. diff --git a/ralph_loop/cli.py b/ralph_loop/cli.py index da6a240..e117751 100644 --- a/ralph_loop/cli.py +++ b/ralph_loop/cli.py @@ -2,6 +2,7 @@ from __future__ import annotations import argparse +import concurrent.futures import os import re import shlex @@ -544,23 +545,28 @@ def _filter_to_still_open_prs(pr_numbers: List[int]) -> List[int]: swallow stale PRs because of a flaky network. """ kept: List[int] = [] - for pr in pr_numbers: + + def _check_pr(pr: int) -> Tuple[int, bool, Optional[CommandError]]: try: - still_open = _pr_is_still_open(pr) + return pr, _pr_is_still_open(pr), None except CommandError as exc: - _print_step( - "Could not confirm PR #{} open state ({}); keeping it in the " - "fan-out set.".format(pr, exc) - ) - kept.append(pr) - continue - if still_open: - kept.append(pr) - else: - _print_step( - "PR #{} is no longer open (per gh pr view); skipping " - "fan-out spawn.".format(pr) - ) + return pr, True, exc + + with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: + for pr, still_open, exc in executor.map(_check_pr, pr_numbers): + if exc: + _print_step( + "Could not confirm PR #{} open state ({}); keeping it in the " + "fan-out set.".format(pr, exc) + ) + kept.append(pr) + elif still_open: + kept.append(pr) + else: + _print_step( + "PR #{} is no longer open (per gh pr view); skipping " + "fan-out spawn.".format(pr) + ) return kept