fix: replace O(teams x members) REST scan in GetUserTeams with GraphQL - #2718
Closed
sav-hostaway wants to merge 1 commit into
Closed
sav-hostaway wants to merge 1 commit into
sav-hostaway wants to merge 1 commit into
Conversation
GetUserTeams listed every team in the organisation and then paged every team's members looking for one user. On a 47-team organisation that is ~48 API requests per call, and populatePolicyFieldsForJobs calls it once for the requester plus once per PR approver, so a digger comment waits 9-27s before its job is dispatched. Two GraphQL queries replace the scan: one filters teams by userLogins, the other builds the team-to-parent map. The parent walk is needed for equivalence, not just completeness: userLogins matches direct membership only, while the REST members endpoint also lists members inherited from child teams, so a naive swap drops parent teams and silently narrows any policy that names one. Measured against a 47-team organisation: before: 48 API requests, 21.3s after: 2 API requests, 1.2s Both return the same team names. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GetUserTeamsanswers "which teams is this user in" by listing every team in the organisation and then paging through every team's members looking for that one login. That is one request per team, plus one per page of each team's members.populatePolicyFieldsForJobscalls it once for the requester and once per PR approver, so the cost lands directly on the latency between adigger plan/digger applycomment and the job actually being dispatched.On a 47-team organisation, measured:
Both return the same team names. In production backend logs this showed up as a 9-27s gap (median 19s, n=19) between
Successfully set PR statusandComputed policy fields for jobs, bimodal depending on whether the PR had an approver, and uncorrelated with the number of projects in the batch.Why two queries and not one
The obvious fix is a single
teams(userLogins: [$login])query. That returns the wrong answer.userLoginsmatches direct membership only, while the REST/orgs/{org}/teams/{slug}/membersendpoint also lists members inherited from child teams. On an organisation whereteam-devopshas parentengineering:So a naive swap silently drops parent teams, and any
access-policynaming a parent team quietly stops matching. That is the same class of bug #2545 was fixing, in the opposite direction.This change therefore runs a second query for the organisation's team-to-parent map and walks the chain upward from each direct team, which reproduces the REST semantics exactly. The walk carries a
seenset so a cycle cannot hang the request.Notes
go-githubclient viaClient.NewRequest/Client.Do.ci.PullRequestServiceimplementations for GitLab, Azure and Bitbucket are untouched.errorsarray is checked explicitly.Testing
go build ./...andgo vet ./ci/github/clean,gofmtcleango test ./ci/...passes, other than the pre-existingTestListRepositoriesReturnsAllRepositiesfailure which needsGITHUB_APP_IDset and fails identically on an unpatched tree🤖 Generated with Claude Code