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.

@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.

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

❌ Patch coverage is 82.14286% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 33.62%. Comparing base (50d4822) to head (5ce3bea).

Files with missing lines Patch % Lines
client/client.go 82.14% 8 Missing and 2 partials ⚠️

❌ 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     9829      +21     
==========================================
+ Hits         3294     3305      +11     
- Misses       6252     6260       +8     
- Partials      262      264       +2     

☔ 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.

client/client.go Outdated
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

@SoulPancake
Copy link
Member

@AltuisticIsopod Any chance you could add the nil checks?

@AltuisticIsopod
Copy link
Author

Sure, I will do that.

@AltuisticIsopod
Copy link
Author

AltuisticIsopod commented Dec 21, 2025

@SoulPancake I have added nil checks along with the authentication error check.

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 4 comments.


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

client/client.go Outdated

err = deleteGroup.Wait()
deleteResponses, err := deletePool.Wait()
// If an error was returned then it will be an authentication error so we want to return
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

This comment is misleading. The error handling checks specifically for authentication errors, but non-authentication errors can also occur (e.g., validation errors, rate limit errors, internal errors). When a non-authentication error occurs, it will be silently ignored, and a nil singleResponse will be returned. Consider either handling all error types explicitly or updating the comment to reflect the actual behavior.

Suggested change
// If an error was returned then it will be an authentication error so we want to return
// At this point, any non-nil err will be an authentication error (non-authentication
// errors from chunk operations are ignored in the goroutines), so we return it directly.

Copilot uses AI. Check for mistakes.
@senojj
Copy link

senojj commented Dec 23, 2025

Why are we migrating from errgroup to conc? The PR description is not clear about that.

@dyeam0
Copy link
Member

dyeam0 commented Jan 6, 2026

Why are we migrating from errgroup to conc? The PR description is not clear about that.

Hey @senojj, I think it stems from consistency changes. It's mentioned here (#193) by @rhamzeh.

@senojj
Copy link

senojj commented Jan 6, 2026

Hey @senojj, I think it stems from consistency changes. It's mentioned here (#193) by @rhamzeh.

@dyeam0 I see. I primarily ask because in core we are migrating from conc to errgroup.

@rhamzeh
Copy link
Member

rhamzeh commented Jan 6, 2026

@senojj our reasons for migrating to conc are not major, but we do want consistency - so either conc or errgroup, and have that pattern established for all future requests that do batching.

As for why conc over errgroup - it has a better DX and workflow, e.g.

  • We have to hold errors, because by default it returns on the first error encountered - but we do want to return on first error in case of context cancellation or authentication errors. Handling this is doable in errgroup, but easier and cleaner in conc
  • errgroup does not properly handle panics (a problem we don't currently handle in our existing code)
  • Better support for generics, so we should be able to simplify some of our code

That said, if there's a better argument to be made for errgroup, we can definitely consider sticking with that

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

6 participants