Skip to content

Conversation

@AltuisticIsopod
Copy link

@AltuisticIsopod AltuisticIsopod commented Oct 17, 2025

Replace errgroup with conc pool in WriteExecute method

Description

  • Replace errgroup with conc pool for parallel write/delete operations
  • Use errors.As() instead of type assertion for authentication error detection
  • Handle wrapped errors from conc pool using errors.As() in both client and test
  • Add nil check before dereferencing singleResponse to prevent panics
  • Update test to use errors.As() for proper error unwrapping

This PR only moved "Write" to use Conc

References

#193

Review Checklist

  • I have clicked on "allow edits by maintainers".
  • I have added documentation for new/changed functionality in this PR or in a PR to openfga.dev [Provide a link to any relevant PRs in the references section above]
  • The correct base branch is being used, if not main
  • I have added tests to validate that the change in functionality is working as expected

@AltuisticIsopod AltuisticIsopod requested a review from a team as a code owner October 17, 2025 21:58
@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Oct 17, 2025

CLA Signed

The committers listed above are authorized under a signed CLA.

  • ✅ login: SoulPancake / name: Anurag Bandyopadhyay (4bf921d)

@coderabbitai
Copy link

coderabbitai bot commented Oct 17, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The changes replace concurrent error-group parallelism with a pool-based approach in batch write and delete operations, add four new public methods to the SdkClient interface for managing authorization model and store IDs, and improve error handling by using the errors.As package for safer type assertions across the client and test code.

Changes

Cohort / File(s) Summary
Batch processing parallelism refactor
client/client.go
Replaced error-group concurrent pattern with pool-based workers (pool.NewWithResults with WithContext and WithMaxGoroutines) for WriteExecute and Delete chunk processing; switched error handling to use errors.As for FgaApiAuthenticationError classification
Public API surface expansion
client/client.go
Added four new public methods to SdkClient interface: SetAuthorizationModelId(string) error, GetAuthorizationModelId() (string, error), SetStoreId(string) error, GetStoreId() (string, error); implemented on OpenFgaClient with ULID format validation and config storage
Error handling improvements
client/client.go, client/client_test.go
Added standard errors package import and replaced direct type assertions with errors.As checks for robust FgaApiAuthenticationError detection across multiple code paths

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

The changes introduce multiple distinct patterns: a significant parallelism refactor in critical write/delete paths requiring verification of pool-worker error flow, new public API methods with straightforward validation logic, and consistent but distributed error handling improvements across two files that each require separate reasoning.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title "replace errgroup with conc pool in WriteExecute method" directly aligns with the primary technical objective stated in the PR description. The title accurately identifies the main refactoring work: replacing the concurrent error-group approach with a conc pool-based approach for parallel operations. While the changeset includes additional modifications such as new public API methods (SetAuthorizationModelId, GetAuthorizationModelId, SetStoreId, GetStoreId) and error handling improvements using errors.As(), the title captures the core technical change that drives the majority of the code review effort. The title is specific, clear, and would enable a teammate reviewing the git history to understand the primary refactoring being performed.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
client/client_test.go (1)

1738-1740: Align this test with errors.As for consistency

Use errors.As here too to avoid panics on wrapped errors.

-        if _, ok := err.(openfga.FgaApiAuthenticationError); !ok {
-            t.Fatalf("Expected an api auth error")
-        }
+        var authErr openfga.FgaApiAuthenticationError
+        if !errors.As(err, &authErr) {
+            t.Fatalf("Expected an api auth error")
+        }
client/client.go (2)

1792-1823: Cancel peers on first auth error

Pools don’t cancel sibling tasks; previous errgroup did via context. Add WithCancelOnError so an auth failure stops in-flight work.

- writePool := pool.NewWithResults[*ClientWriteResponse]().WithContext(request.GetContext()).WithMaxGoroutines(int(maxParallelReqs))
+ writePool := pool.NewWithResults[*ClientWriteResponse]().
+   WithContext(request.GetContext()).
+   WithMaxGoroutines(int(maxParallelReqs)).
+   WithCancelOnError()

- deletePool := pool.NewWithResults[*ClientWriteResponse]().WithContext(request.GetContext()).WithMaxGoroutines(int(maxParallelReqs))
+ deletePool := pool.NewWithResults[*ClientWriteResponse]().
+   WithContext(request.GetContext()).
+   WithMaxGoroutines(int(maxParallelReqs)).
+   WithCancelOnError()

Also applies to: 1837-1872


1830-1834: Use deleteChunkSize when chunking deletes

Currently uses writeChunkSize; same value today, but confusing.

-            end := int(math.Min(float64(i+writeChunkSize), float64(len(request.GetBody().Deletes))))
+            end := int(math.Min(float64(i+deleteChunkSize), float64(len(request.GetBody().Deletes))))
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b316fa5 and 3f0f714.

📒 Files selected for processing (2)
  • client/client.go (5 hunks)
  • client/client_test.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
client/client_test.go (1)
errors.go (1)
  • FgaApiAuthenticationError (47-60)
client/client.go (1)
errors.go (1)
  • FgaApiAuthenticationError (47-60)
🔇 Additional comments (2)
client/client_test.go (1)

1779-1781: Good switch to errors.As for auth error unwrapping

Safer and matches wrapped errors from conc pool. LGTM.

Also applies to: 1798-1800

client/client.go (1)

1811-1819: Nice: errors.As + nil-check avoid panics and classify auth errors correctly

This correctly bubbles auth errors while still aggregating non-auth failures per item. LGTM.

Also applies to: 1857-1866

@AltuisticIsopod
Copy link
Author

AltuisticIsopod commented Oct 18, 2025

  • Removed manual slice management and indexing for write/delete operations
  • Used conc pool's automatic result collection instead of manual assignment

@AltuisticIsopod
Copy link
Author

AltuisticIsopod commented Oct 18, 2025

Hey @rhamzeh, I have replaced errgroup with conc for Write. Can you review and let me know if you find any issues.
Can you please add Hacktoberfest label to this issue? Thank you.

@dyeam0
Copy link
Member

dyeam0 commented Nov 3, 2025

Hi @AltuisticIsopod, same as with openfga/sdk-generator#653, we'll assign someone to review your PR. Thanks.

@dyeam0 dyeam0 linked an issue Nov 3, 2025 that may be closed by this pull request
@dyeam0 dyeam0 requested a review from SoulPancake November 3, 2025 05:02
@codecov-commenter
Copy link

codecov-commenter commented Nov 3, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 33.62%. Comparing base (50d4822) to head (4bf921d).

❌ Your project status has failed because the head coverage (33.62%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #249      +/-   ##
==========================================
+ Coverage   33.58%   33.62%   +0.04%     
==========================================
  Files         115      115              
  Lines        9808     9814       +6     
==========================================
+ Hits         3294     3300       +6     
  Misses       6252     6252              
  Partials      262      262              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@SoulPancake SoulPancake requested a review from Copilot November 3, 2025 05:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the WriteExecute method to use github.com/sourcegraph/conc/pool instead of golang.org/x/sync/errgroup for parallel processing, and updates error handling to use errors.As() instead of type assertions for checking authentication errors.

Key changes:

  • Replaced errgroup with pool.NewWithResults for managing concurrent write and delete operations
  • Updated authentication error checking from type assertions (err.(Type)) to errors.As() for better error unwrapping support
  • Updated corresponding test cases to use the new error checking pattern

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
client/client.go Refactored WriteExecute to use conc pool library for concurrent operations and updated error handling to use errors.As()
client/client_test.go Updated test cases to use errors.As() for authentication error checking
Comments suppressed due to low confidence (1)

client/client.go:1860

  • The logic assumes writeResponses and deleteResponses contain non-nil pointers, but the pool returns []*ClientWriteResponse. If any goroutine returns nil for the response (which happens in lines 1801 and 1842 when authentication errors occur), this will cause a nil pointer dereference when accessing .Writes or .Deletes. Add nil checks before dereferencing: if writeResponse != nil { response.Writes = append(...) }
	for _, writeResponse := range writeResponses {
		response.Writes = append(response.Writes, writeResponse.Writes...)
	}

	for _, deleteResponse := range deleteResponses {
		response.Deletes = append(response.Deletes, deleteResponse.Deletes...)
	}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@SoulPancake SoulPancake added this pull request to the merge queue Dec 10, 2025
@SoulPancake SoulPancake removed this pull request from the merge queue due to a manual request Dec 10, 2025
@SoulPancake SoulPancake self-requested a review December 10, 2025 10:43
Copy link
Member

@SoulPancake SoulPancake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG for WriteExecute, Can you possibly also do this for ClientBatchCheck? @AltuisticIsopod

@AltuisticIsopod
Copy link
Author

Sure, I will do that.

@SoulPancake SoulPancake requested a review from Copilot December 12, 2025 06:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1797 to +1799
var authErr fgaSdk.FgaApiAuthenticationError
// If an error was returned then it will be an authentication error so we want to return
if errors.As(err, &authErr) {
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "If an error was returned then it will be an authentication error" but this is inaccurate. The errors.As check only handles authentication errors, but other types of errors could also be returned from client.WriteExecute. Non-authentication errors would still pass through and return singleResponse (which could be nil) with err=nil, leading to potential nil pointer dereferences when iterating over writeResponses.

Suggested change
var authErr fgaSdk.FgaApiAuthenticationError
// If an error was returned then it will be an authentication error so we want to return
if errors.As(err, &authErr) {
if err != nil {

Copilot uses AI. Check for mistakes.
// If an error was returned then it will be an authentication error so we want to return
if errors.As(err, &authErr) {
return nil, err
}
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential nil pointer dereference. If client.WriteExecute returns a non-authentication error with singleResponse=nil, the code at line 1799 will return nil for the error (since errors.As will be false), but singleResponse will be nil. This nil response will then be dereferenced at line 1854 causing a panic. The code should check if err is not nil (for any error type) and return it, or ensure singleResponse is not nil before returning it.

Suggested change
}
}
if err != nil {
return nil, err
}

Copilot uses AI. Check for mistakes.
Comment on lines +1839 to +1840
var authErr fgaSdk.FgaApiAuthenticationError
if errors.As(err, &authErr) {
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential nil pointer dereference. If client.WriteExecute returns a non-authentication error with singleResponse=nil, the code will return nil with no error (since errors.As will be false for non-authentication errors). This nil response will then be dereferenced at line 1858 causing a panic. The code should check if err is not nil (for any error type) and return it, or ensure singleResponse is not nil before returning it.

Suggested change
var authErr fgaSdk.FgaApiAuthenticationError
if errors.As(err, &authErr) {
if err != nil {

Copilot uses AI. Check for mistakes.
Comment on lines +2267 to 2271
// If an error was returned then it will be an authentication error so we want to return
if errors.As(err, &authErr) {
return nil, err
}

Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "If an error was returned then it will be an authentication error" but this is inaccurate. The errors.As check only handles authentication errors, but other types of errors could also be returned from client.CheckExecute. Non-authentication errors would pass through to be stored in the Error field of the response, but singleResponse could be nil, leading to a potential nil pointer dereference at line 2276.

Suggested change
// If an error was returned then it will be an authentication error so we want to return
if errors.As(err, &authErr) {
return nil, err
}
// If the error is an authentication error, return it immediately.
if errors.As(err, &authErr) {
return nil, err
}
// If any other error occurred and singleResponse is nil, avoid nil pointer dereference.
if err != nil && singleResponse == nil {
return &batchCheckResult{
Index: index,
Response: ClientBatchCheckClientSingleResponse{
Request: checkBody,
ClientCheckResponse: ClientCheckResponse{}, // zero value
Error: err,
},
}, nil
}

Copilot uses AI. Check for mistakes.
Comment on lines +2272 to +2276
return &batchCheckResult{
Index: index,
Response: ClientBatchCheckClientSingleResponse{
Request: checkBody,
ClientCheckResponse: *singleResponse,
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential nil pointer dereference. If client.CheckExecute returns a non-authentication error with singleResponse=nil, the code will dereference singleResponse at line 2276 causing a panic. The code should check if singleResponse is nil before dereferencing it, especially since the err is being stored in the response for non-authentication errors.

Suggested change
return &batchCheckResult{
Index: index,
Response: ClientBatchCheckClientSingleResponse{
Request: checkBody,
ClientCheckResponse: *singleResponse,
var clientCheckResponse fgaSdk.ClientCheckResponse
if singleResponse != nil {
clientCheckResponse = *singleResponse
}
return &batchCheckResult{
Index: index,
Response: ClientBatchCheckClientSingleResponse{
Request: checkBody,
ClientCheckResponse: clientCheckResponse,

Copilot uses AI. Check for mistakes.
@AltuisticIsopod
Copy link
Author

Hi @SoulPancake , The earlier codebase was only checking for errors of type fgaSdk.FgaApiAuthenticationError. So, I followed the same and I am only catching those errors.

@SoulPancake
Copy link
Member

@AltuisticIsopod
I think adding the nil checks should be good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move ClientBatchCheck and Write to use conc

4 participants