diff --git a/docs/configuration.md b/docs/configuration.md index 37fc97f90..bc9dd4aae 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -159,6 +159,7 @@ Optional array of additional git remotes to track. | Key | Type | Default | Description | |-----|------|---------|-------------| | `concurrency` | integer | -- | Number of concurrent reviews. | +| `max_concurrency` | integer | -- | Max number of concurrent review queue. | | `worktree_dir` | string | -- | Directory for git worktrees used during review. | | `timeout_seconds` | integer | `3600` | Maximum time per review (seconds). | | `max_retries` | integer | `3` | Retry count on transient failures. | diff --git a/src/reviewer.rs b/src/reviewer.rs index 383e71711..d4b9928f4 100644 --- a/src/reviewer.rs +++ b/src/reviewer.rs @@ -96,7 +96,8 @@ impl Reviewer { /// * `db` - The database connection. /// * `settings` - Application settings. pub async fn new(db: Arc, settings: Settings) -> Self { - let concurrency = settings.review.concurrency; + let mut concurrency = settings.review.concurrency; + let max_concurrency = settings.review.max_concurrency; let repo_path = PathBuf::from(&settings.git.repository_path); let baseline_registry = @@ -129,12 +130,17 @@ impl Reviewer { // On average, an active patch review consumes ~3 LLM slots over its execution lifetime. // Thus, the global LLM request semaphore is scaled to (concurrency * 3) to fully // saturate LLM capacity while gating local processes/worktrees strictly to `concurrency`. - let llm_concurrency = if concurrency < 2 { + let mut llm_concurrency = if concurrency < 2 { 1 } else { std::cmp::max(1, concurrency * 3) }; + if max_concurrency.is_some() { + concurrency = concurrency.min(max_concurrency.unwrap_or(usize::MAX)); + llm_concurrency = llm_concurrency.min(max_concurrency.unwrap_or(usize::MAX)); + } + Self { db, settings, diff --git a/src/settings.rs b/src/settings.rs index ff3e79cdc..e9c7f1a17 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -367,6 +367,7 @@ pub struct GitSettings { #[allow(unused)] pub struct ReviewSettings { pub concurrency: usize, + pub max_concurrency: Option, pub worktree_dir: String, #[serde(default = "default_review_timeout")] pub timeout_seconds: u64, @@ -469,6 +470,7 @@ fn default_forge() -> ForgeSettings { #[derive(Debug, Deserialize, Clone)] pub struct LocalReviewReviewSettings { pub concurrency: Option, + pub max_concurrency: Option, } #[derive(Debug, Deserialize, Clone)]