fix: paginate usergroup grants to avoid rate limit cascades - #85
Conversation
|
Claude finished @btipling's task in 1m 0s —— View job PR Review: Paginate usergroup grants
Overall: Good direction — batching the N+1 Bug: Potential panic if membership shrinks between pages
page := groupMembers[offset:end] // panics if offset > len(groupMembers)Add a bounds check after computing if offset >= len(groupMembers) {
return nil, &resource.SyncOpResults{Annotations: outputAnnotations}, nil
}Efficiency: Re-fetching the full member list on every page
Nit: Error prefixPer the repo's CLAUDE.md convention, errors should include a connector prefix (e.g. Summary: The core pagination logic is sound and addresses the root cause well. The one must-fix is the bounds check to guard against membership changes between pages — without it, this can panic in production. |
The Grants method for usergroups was fetching all group members then calling users.info for each one sequentially in a single call. For large groups this exhausts the Slack rate limit, and on retry the SDK restarts the entire loop from member 0, hitting the limit at the same point. Now processes members in batches of 20 per page. When a rate limit error occurs mid-batch, the SDK retries just that batch. Completed batches are not re-fetched. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
75ffebd to
830a4a6
Compare
|
Claude finished @btipling's task in 43s —— View job PR Review: Paginate usergroup grants
Overall: This is a well-targeted fix. Batching the N+1 Re-fetching the full member list on every page
Membership instability between pagesThe bounds check at line 157 correctly prevents a panic when the group shrinks. However, if members are added or removed between pages, the offset-based windowing can silently skip members or emit duplicate grants (since the underlying list order may shift). This is inherent to offset-based pagination over a mutable list — it's not easily fixable without Slack providing a stable cursor. Just worth documenting as a known limitation. In practice, membership churn during a sync window is rare enough that this is fine. Nit: Error prefix consistencyThe new error at line 152 correctly uses the Verdict: The core logic is sound, the bounds check is in place, and this should resolve the cascading 429s for large usergroups. Looks good to merge. 👍 |
WrapError was re-wrapping all unrecognized errors as codes.Unknown, including errors from businessPlusClient/uhttp that already had a proper gRPC code (e.g. codes.Unavailable for 429s). This prevented the SDK from retrying these errors. Now checks if the error already has a gRPC code and preserves it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Claude finished @btipling's task in 51s —— View job PR Review: Paginate usergroup grants
Overall: Looks good to merge 👍 This is a clean, well-targeted fix. Batching the N+1 Commit 1:
|
Summary
users.infoper member in a single Grants call — large groups exhaust the Slack rate limit, and SDK retries restart from member 0NextPageTokenso completed batches are preserved across retriesContext
Resolves CXH-1301
Datadog logs show continuous 429s on
/api/users.infowithRetry-After: 4. The previous fix (v0.1.21) added rate limit annotations toSyncOpResults, but the fundamental issue was the N+1 unbatched loop — every retry re-fetched all members from scratch.Test plan
🤖 Generated with Claude Code