Independent prConcurrentLimit/branchConcurrentLimit counters per packageRule scope, within a single scan #45352
florianwakam
started this conversation in
Suggest an Idea
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Feature request: independent prConcurrentLimit/branchConcurrentLimit counters per packageRule scope, within a single scan
Problem
In a monorepo with multiple teams/folders, a single
prConcurrentLimit/branchConcurrentLimitis enforced repo-wide, regardless of whichpackageRuleassigned the value to a given branch.getConcurrentPrsCount()/getConcurrentBranchesCount()(lib/workers/repository/process/limits.ts) always count every open Renovate branch/PR in the whole repository extraction, then compare that single total against whatever limit the branch's own rules resolved to.Concretely: if we set
this does not give team-a 5 slots and team-b 5 slots independently. Both thresholds are compared to the same repo-wide count, so the first team whose branches fill that shared pool blocks the other team's branches from ever being created — even if that team has zero open PRs of its own.
We hit this in production: one run created 2 PRs, filled the (then) global limit of 10, and blocked 115 other candidate branches across every other folder in the monorepo — including two teams that had zero open PRs at the time. The teams whose PRs happened to sit unmerged effectively starved every other team, purely because of scan order and merge cadence, with no relationship to how many updates each team actually had pending.
What we verified (not just theorizing)
lib/workers/repository/process/limits.tson the pinned43.285.0: the counting functions have no per-rule/per-group bucketing — it's a single count, always.RENOVATE_DRY_RUN=full, real tokens, real repo) — one scoped to team-a's folder viaincludePaths, one scoped to team-b's folder, each with its ownbranchPrefix. Log evidence:Open PR Count: 0, Existing Branch Count: 0repeated for every candidate branch.Open PR Count: 2, Existing Branch Count: 2repeated for every candidate branch.packageRuleset the numeric limit.The only working workaround today has real costs
The only way we found to get a genuinely independent per-scope counter is to run Renovate as N separate passes in one scan/job (or N separate scheduled jobs), each with its own
includePaths+ a scope-specificbranchPrefix(required — without a distinct prefix, each pass's stale-branch pruning would delete every other scope's branches, sincepruneStaleBranchesonly recognizes branches matchingbranchPrefix). This works — we validated it — but:ensureDependencyDashboardPATCHes the issue body from scratch using only that pass's own branch list, so whichever scope's pass writes last wins, and every other scope's section disappears from the dashboard entirely (their PRs still exist on the platform, they're just no longer listed in the issue). If the passes run in parallel — the default for a CI matrix unless concurrency is capped to 1 — which scope "wins" is non-deterministic: it depends on which job happens to finish last on a given night, not on any config. The only real fix we found is one dashboard issue per scope (distinctdependencyDashboardTitleper pass), which is a bigger behavior/UX change than we wanted just to fix a concurrency limit — teams lose the single consolidated view.packageRulemeant to apply repo-wide by dependency name (not by path) — e.g. "never touch this dependency wherever it appears" — silently stops firing outside the one scoped pass whose config module happens to define it, because the files it would need to see are outside that pass'sincludePaths.None of this is a criticism of the workaround being hard to implement — it's that it's a disproportionate amount of infrastructure to build just to get what feels like it should be a
packageRules-level concern.Request
A way to scope
prConcurrentLimit/branchConcurrentLimitcounting itself (not just the threshold value) to the set of branches matched by a given rule/group, within a single scan — e.g. counting only branches whose resolved packageRule chain included a givengroupSlug/rule identifier, rather than every branch in the run. That would let a monorepo express "team-a gets up to 5 concurrent, team-b gets up to 5 concurrent" as plain config, without needing to fan out into multiple scans, and without breaking the Dependency Dashboard's single-issue model the way the multi-scan workaround does.All reactions