diff --git a/.jules/bolt.md b/.jules/bolt.md index 3708540..91810df 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -13,3 +13,6 @@ ## 2026-06-14 - Deferring Pathlib Operations in Hot Paths **Learning:** In highly repetitive loops like file scanners (e.g., iterating through thousands of safe files), preemptively calculating `Path.relative_to()` and sanitizing strings adds significant cumulative overhead. Pathlib operations internally parse paths, check parts, and construct new objects, which is extremely expensive when executed on a per-file basis unconditionally. **Action:** Always defer expensive path computations (like converting paths to relative or string sanitization) until *after* the fast-path condition (like a regex match) triggers. This drastically cuts down on unnecessary string operations for clean files. +## 2024-06-16 - Parallelize Subprocess CLI Calls +**Learning:** Sequential, synchronous execution of `subprocess.run` (like calling the GitHub CLI) across multiple items (like PRs) is a significant I/O bottleneck. +**Action:** Use `concurrent.futures.ThreadPoolExecutor` with `functools.partial` and `executor.map` to safely parallelize I/O-bound subprocess executions, significantly reducing overall script runtime. diff --git a/scripts/ci/pr_review_merge_scheduler.py b/scripts/ci/pr_review_merge_scheduler.py index a8fee70..f8ebe27 100644 --- a/scripts/ci/pr_review_merge_scheduler.py +++ b/scripts/ci/pr_review_merge_scheduler.py @@ -6,6 +6,8 @@ import os import subprocess import sys +import concurrent.futures +from functools import partial from dataclasses import dataclass from typing import Any @@ -330,17 +332,18 @@ def main(argv: list[str]) -> int: if not args.repo: raise SystemExit("--repo is required") prs = fetch_open_prs(args.repo, args.max_prs) - decisions = [ - inspect_pr( - args.repo, - pr, - dry_run=args.dry_run, - trigger_reviews=args.trigger_reviews, - enable_auto_merge_flag=args.enable_auto_merge, - workflow=args.review_workflow, - ) - for pr in prs - ] + + inspect_func = partial( + inspect_pr, + args.repo, + dry_run=args.dry_run, + trigger_reviews=args.trigger_reviews, + enable_auto_merge_flag=args.enable_auto_merge, + workflow=args.review_workflow, + ) + with concurrent.futures.ThreadPoolExecutor() as executor: + decisions = list(executor.map(inspect_func, prs)) + print_summary(decisions, dry_run=args.dry_run) return 0