Skip to content

Conversation

jimmyjames
Copy link
Contributor

@jimmyjames jimmyjames commented Aug 15, 2025

sync changes from geneator:

Summary by CodeRabbit

  • New Features

    • Per-tuple write results surfaced (SUCCESS/FAILURE) in write responses.
    • Optional non-transactional write mode with chunking and partial success reporting.
    • Enhanced retry/backoff support for HTTP requests.
  • Bug Fixes

    • More robust handling of malformed response headers to avoid metric parsing errors.
    • Thread-safe jitter for backoff to improve reliability.
    • Metrics now respect global OpenTelemetry configuration.
  • Tests

    • Added extensive unit and integration tests covering retries, backoff, and write behaviors.
  • Chores

    • Updated example app to use environment-based credentials.

@jimmyjames jimmyjames requested a review from a team as a code owner August 15, 2025 16:20
Copy link
Contributor

coderabbitai bot commented Aug 15, 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

Adds per-tuple write result modeling and two-mode (transactional/non-transactional) write handling in the client. Introduces retry/backoff utilities and enhances HTTP retry telemetry and header parsing. Updates metrics to use GlobalOpenTelemetry. Refreshes examples, integration tests, and Gradle wrapper/settings. Expands ClientWriteResponse with detailed write/delete results.

Changes

Cohort / File(s) Summary of Changes
Client write result modeling
src/main/java/dev/openfga/sdk/api/client/model/ClientWriteResponse.java, .../model/ClientWriteSingleResponse.java, .../model/ClientWriteStatus.java
Added per-tuple write/delete result structures, new constructor and getters in ClientWriteResponse, and new immutable result class and enum (SUCCESS/FAILURE).
Client write flow logic
src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java
Implemented transactional (default) and non-transactional write modes; chunking, parallel processing, per-tuple aggregation, and authentication error handling. Updated Javadoc.
HTTP retry/telemetry
src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java
Added resend-count telemetry on retries; made fga-query-duration-ms parsing robust to malformed values.
Retry/backoff utilities
src/main/java/dev/openfga/sdk/util/ExponentialBackoff.java, .../util/RetryAfterHeaderParser.java, .../util/RetryStrategy.java
Added retry utilities; ExponentialBackoff now uses ThreadLocalRandom and validates baseDelay (non-null, non-negative, non-zero).
Metrics plumbing
src/main/java/dev/openfga/sdk/telemetry/Metrics.java
Switched meter acquisition to GlobalOpenTelemetry.
Unit tests (client/util)
src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java, .../util/ExponentialBackoffTest.java
Expanded tests for new write-response semantics and non-transactional failure handling; added/extended backoff validation tests (includes duplicated test methods).
Integration tests and resources
src/test-integration/java/dev/openfga/sdk/example/Example1.java, src/test-integration/...
Added/updated integration tests covering new behaviors; environment-based credentials; expanded write payloads.
Examples
example/example1/src/main/java/dev/openfga/sdk/example/Example1.java
Switched credentials to env vars; updated write examples to multiple/duplicate tuples.
Build configuration
gradle/wrapper/gradle-wrapper.properties, example/example1/gradle/wrapper/gradle-wrapper.properties, settings.gradle
Upgraded Gradle wrapper to 8.14.3; added pluginManagement repositories (Gradle Portal, Maven Central).

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant OpenFgaClient
  participant FGA_API

  Note over OpenFgaClient: Transactional mode
  App->>OpenFgaClient: writeTuples(writes, deletes)
  OpenFgaClient->>FGA_API: POST /write (all tuples)
  FGA_API-->>OpenFgaClient: 2xx
  OpenFgaClient-->>App: ClientWriteResponse (all inputs marked SUCCESS)

  Note over OpenFgaClient: Non-Transactional mode
  App->>OpenFgaClient: writeTuples(writes, deletes, nonTx opts)
  loop chunks
    OpenFgaClient->>FGA_API: POST /write (chunk)
    alt 2xx
      OpenFgaClient-->>OpenFgaClient: mark chunk tuples SUCCESS
    else Auth error
      OpenFgaClient-->>App: throw FgaApiAuthenticationError
    else Other error
      OpenFgaClient-->>OpenFgaClient: mark chunk tuples FAILURE with error
    end
  end
  OpenFgaClient-->>App: Aggregated per-tuple statuses
Loading
sequenceDiagram
  participant OpenFgaClient
  participant HttpRequestAttempt
  participant RetryStrategy
  participant FGA_API

  OpenFgaClient->>HttpRequestAttempt: send(request)
  HttpRequestAttempt->>FGA_API: HTTP request
  FGA_API-->>HttpRequestAttempt: response/error
  alt retryable error/status
    HttpRequestAttempt->>RetryStrategy: shouldRetry(response/error)
    RetryStrategy-->>HttpRequestAttempt: decision, delay (uses RetryAfterHeaderParser / ExponentialBackoff)
    HttpRequestAttempt-->>HttpRequestAttempt: record resend-count telemetry
    HttpRequestAttempt->>FGA_API: retry after delay
  end
  HttpRequestAttempt-->>OpenFgaClient: final response/error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • feat: improved retry handling #186 — Introduces the same retry/backoff utilities and integrates them into HTTP retry logic, overlapping directly with this PR’s utility and client retry changes.

Suggested reviewers

  • rhamzeh
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/sync-gen

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 2

🧹 Nitpick comments (21)
gradle/wrapper/gradle-wrapper.properties (1)

3-3: Pin the wrapper with distributionSha256Sum for supply-chain hardening.

Add the checksum to verify the downloaded Gradle distribution. Optional: keep distribution type consistent across the repo (root uses -all, example uses -bin).

Apply this change (replace placeholder with the actual checksum):

 distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
+distributionSha256Sum=<replace-with-gradle-8.14.3-all.zip-sha256>

You can use the script from my other comment to resolve and inject the correct SHA.

settings.gradle (1)

1-6: Optional: also centralize dependency repositories via dependencyResolutionManagement.

If you want to prevent subprojects from declaring their own repositories ad hoc and ensure consistent artifact resolution, add a top-level dependencyResolutionManagement block.

You could add:

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_PROJECT) // or FAIL_ON_PROJECT_REPOS
    repositories {
        mavenCentral()
        // add any others you need (e.g., mavenLocal(), company mirrors)
    }
}
src/main/java/dev/openfga/sdk/telemetry/Metrics.java (2)

38-38: Prefer meterBuilder and set instrumentation version (optional, forward-looking).

Using meterBuilder allows setting an instrumentation version and schema, which improves observability and attribution in backends. This also avoids reliance on the deprecated get(name) style in newer OTel APIs.

Apply:

-        this.meter = GlobalOpenTelemetry.get().getMeterProvider().get("openfga-sdk");
+        this.meter = GlobalOpenTelemetry.get()
+                .getMeterProvider()
+                .meterBuilder("openfga-sdk")
+                .setInstrumentationVersion(
+                        Metrics.class.getPackage() != null ? Metrics.class.getPackage().getImplementationVersion() : null)
+                .build();

Note: getImplementationVersion() reads from your JAR manifest’s Implementation-Version. If unavailable, it gracefully passes null (allowed).


38-38: Thread-safety of metric caches (optional).

counters and histograms are HashMaps accessed without synchronization; if Metrics is used across threads, consider ConcurrentHashMap with computeIfAbsent.

Outside this line range, consider:

private final Map<String, LongCounter> counters = new ConcurrentHashMap<>();
private final Map<String, DoubleHistogram> histograms = new ConcurrentHashMap<>();

// Usage:
counters.computeIfAbsent(counter.getName(),
    name -> meter.counterBuilder(name).setDescription(counter.getDescription()).build());
src/main/java/dev/openfga/sdk/util/ExponentialBackoff.java (2)

64-69: Input validation for baseDelay is correct; consider updating Javadoc.

The new checks for negative and zero durations are good and align with tests. Consider documenting the thrown exceptions and the behavior when retryCount < 0 (currently returns Duration.ZERO).

You might update the Javadoc above calculateDelay(int, Duration) to include:

  • Throws IllegalArgumentException when baseDelay is null, zero, or negative.
  • Returns Duration.ZERO when retryCount is negative.

73-79: Avoid overflow when computing exponential delay (optional).

(long) Math.pow(2, retryCount) * baseDelayMs can overflow before the cap is applied, yielding incorrect negative values for extreme inputs. A saturating doubling loop avoids this.

Apply:

-        long exponentialDelayMs = (long) Math.pow(2, retryCount) * baseDelayMs;
-
-        // Cap at maximum delay
-        long maxDelayMs = MAX_DELAY_SECONDS * 1000L;
-        if (exponentialDelayMs > maxDelayMs) {
-            exponentialDelayMs = maxDelayMs;
-        }
+        long maxDelayMs = MAX_DELAY_SECONDS * 1000L;
+        long exponentialDelayMs = baseDelayMs;
+        for (int i = 0; i < retryCount && exponentialDelayMs < maxDelayMs; i++) {
+            if (exponentialDelayMs > maxDelayMs / 2) { // prevent overflow
+                exponentialDelayMs = maxDelayMs;
+                break;
+            }
+            exponentialDelayMs *= 2;
+        }
+        if (exponentialDelayMs > maxDelayMs) {
+            exponentialDelayMs = maxDelayMs;
+        }

This keeps semantics while ensuring no overflow even with large retry counts.

src/test/java/dev/openfga/sdk/util/ExponentialBackoffTest.java (1)

198-234: Input validation tests for baseDelay are correct and aligned with implementation

  • Negative base delay (two-arg) and (three-arg with Random) correctly assert the exact messages.
  • Zero base delay case is also covered with the expected message.

To reduce repetition and improve consistency:

  • Consider consolidating these three tests into a parameterized test.
  • Optionally unify on a single assertion style (either AssertJ’s assertThatThrownBy or JUnit’s assertThrows) across the class for consistency.
src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java (1)

185-197: Simplify header parsing and trim value to avoid false negatives

Minor cleanup: avoid calling firstValue twice and trim the header before parsing to reduce NumberFormatException on values with incidental whitespace. Consider optional debug logging on malformed values.

Apply this diff:

-        if (response.headers().firstValue("fga-query-duration-ms").isPresent()) {
-            String queryDuration =
-                    response.headers().firstValue("fga-query-duration-ms").orElse(null);
-
-            if (!isNullOrWhitespace(queryDuration)) {
-                try {
-                    double queryDurationDouble = Double.parseDouble(queryDuration);
-                    telemetry.metrics().queryDuration(queryDurationDouble, this.getTelemetryAttributes());
-                } catch (NumberFormatException e) {
-                    // Ignore malformed fga-query-duration-ms header values to prevent exceptions
-                    // on otherwise valid responses. The telemetry metric will simply not be recorded.
-                }
-            }
-        }
+        response.headers()
+                .firstValue("fga-query-duration-ms")
+                .ifPresent(queryDuration -> {
+                    if (!isNullOrWhitespace(queryDuration)) {
+                        try {
+                            double queryDurationDouble = Double.parseDouble(queryDuration.trim());
+                            telemetry.metrics().queryDuration(queryDurationDouble, this.getTelemetryAttributes());
+                        } catch (NumberFormatException e) {
+                            // Ignore malformed fga-query-duration-ms header values to prevent exceptions
+                            // on otherwise valid responses. The telemetry metric will simply not be recorded.
+                            // (Optional) add debug log if you want visibility when this occurs.
+                        }
+                    }
+                });
example/example1/src/main/java/dev/openfga/sdk/example/Example1.java (2)

21-23: Environment-based credential wiring looks good; consider validating both ID and secret

Reading issuer, clientId, and clientSecret from env is great. Small robustness nit: the guard currently checks only FGA_CLIENT_ID; consider requiring both ID and SECRET (and optionally issuer) to avoid constructing credentials with a missing secret.

Example adjustment (outside the shown range):

if (System.getenv("FGA_CLIENT_ID") != null && System.getenv("FGA_CLIENT_SECRET") != null) { ... }

105-118: Nice example payload to exercise non-transactional writes; consider printing per-tuple results

Including a duplicate and a different relation is a good way to showcase the new per-tuple write semantics. To highlight the new API surface, consider capturing the ClientWriteResponse and printing each tuple’s status and any message for developer visibility.

Example (outside the shown range):

var writeResponse = fgaClient.write(...).get();
// Pseudocode – adjust getters to actual model names:
writeResponse.getWriteResults().forEach(r ->
    System.out.printf("tuple=%s status=%s msg=%s%n", r.getTupleKey(), r.getStatus(), r.getMessage()));

Also consider extracting the document ID to a local variable to avoid repeating the long literal.

src/test-integration/java/dev/openfga/sdk/example/Example1.java (2)

21-23: Env-driven credentials mirrored in integration example; add a second null-check

Same suggestion as the example app: ensure both FGA_CLIENT_ID and FGA_CLIENT_SECRET are present before constructing credentials to avoid partially configured auth in CI.


104-118: Good end-to-end payload for non-transaction mode; consider asserting per-tuple outcomes

Since this runs in integration tests, it could validate the new per-tuple behavior by asserting expected statuses (e.g., duplicate returns failure and owner relation succeeds) when disableTransactions(true) is set.

If assertions are out of scope here, at least log the per-tuple statuses to aid debugging flakiness in CI environments.

src/main/java/dev/openfga/sdk/api/client/model/ClientWriteResponse.java (2)

24-33: Defensive-copy and expose unmodifiable result lists to avoid external mutation

The new writes and deletes fields hold references to caller-provided lists. Since the fields are returned directly via getters, callers can mutate the response afterward. Prefer copying and returning unmodifiable lists to preserve immutability guarantees.

Apply this diff to defensively copy and expose unmodifiable lists:

     public ClientWriteResponse(ApiResponse<Object> apiResponse) {
         this.statusCode = apiResponse.getStatusCode();
         this.headers = apiResponse.getHeaders();
         this.rawResponse = apiResponse.getRawResponse();
-        this.writes = Collections.emptyList();
-        this.deletes = Collections.emptyList();
+        this.writes = Collections.emptyList();
+        this.deletes = Collections.emptyList();
     }

     public ClientWriteResponse(List<ClientWriteSingleResponse> writes, List<ClientWriteSingleResponse> deletes) {
         this.statusCode = 200;
         this.headers = Collections.emptyMap();
         this.rawResponse = "";
-        this.writes = writes != null ? writes : Collections.emptyList();
-        this.deletes = deletes != null ? deletes : Collections.emptyList();
+        this.writes = writes != null ? Collections.unmodifiableList(List.copyOf(writes)) : Collections.emptyList();
+        this.deletes = deletes != null ? Collections.unmodifiableList(List.copyOf(deletes)) : Collections.emptyList();
     }

35-41: Consider preserving HTTP metadata (status, headers, raw) when synthesizing per-tuple responses

This constructor hardcodes statusCode=200, empty headers, and empty raw response. In transactional/non-transactional write paths you already have the API response available; discarding headers (e.g., request IDs, server timing) may reduce diagnosability/telemetry.

Recommend adding an additional constructor to carry HTTP metadata plus the per-tuple results:

// New overload (in addition to the existing constructors)
public ClientWriteResponse(
    int statusCode,
    Map<String, List<String>> headers,
    String rawResponse,
    List<ClientWriteSingleResponse> writes,
    List<ClientWriteSingleResponse> deletes
) {
    this.statusCode = statusCode;
    this.headers = headers != null ? headers : Collections.emptyMap();
    this.rawResponse = rawResponse != null ? rawResponse : "";
    this.writes = writes != null ? Collections.unmodifiableList(List.copyOf(writes)) : Collections.emptyList();
    this.deletes = deletes != null ? Collections.unmodifiableList(List.copyOf(deletes)) : Collections.emptyList();
}

With that in place, callers (e.g., OpenFgaClient.writeTransactions/writeTuples/deleteTuples) can propagate metadata instead of dropping it. Can you confirm if any consumers rely on these headers today?

src/main/java/dev/openfga/sdk/api/client/model/ClientWriteSingleResponse.java (2)

17-17: Make the response holder class final

This is an immutable data holder (final fields, only getters). Declaring the class final prevents unintended subclassing and aligns with its immutable intent.

-public class ClientWriteSingleResponse {
+public final class ClientWriteSingleResponse {

15-16: Add null-safety for required fields (tupleKey, status)

To fail fast and make misuse obvious, guard required fields in the constructor. This prevents obscure NPEs later.

 import dev.openfga.sdk.api.model.TupleKey;
+import java.util.Objects;

 public final class ClientWriteSingleResponse {
@@
     public ClientWriteSingleResponse(TupleKey tupleKey, ClientWriteStatus status, Exception error) {
-        this.tupleKey = tupleKey;
-        this.status = status;
+        this.tupleKey = Objects.requireNonNull(tupleKey, "tupleKey");
+        this.status = Objects.requireNonNull(status, "status");
         this.error = error;
     }

Also applies to: 26-30

.openapi-generator/FILES (1)

320-322: Duplicate file entry detected

src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java appears twice. This can confuse tooling relying on this manifest.

Apply this diff to remove the duplicate:

 src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java
-src/test/java/dev/openfga/sdk/api/OpenFgaApiTest.java
src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java (1)

1269-1344: Solid coverage for non-transactional partial failures; consider asserting error type

Great end-to-end verification: request sequencing, headers, and per-tuple statuses in the response. To further harden this test, add an assertion that the failure’s error is of type FgaApiValidationError and has statusCode=400 to ensure error typing is preserved.

Example enhancement:

assertTrue(writes.get(1).getError() instanceof FgaApiValidationError);
assertEquals(400, ((FgaApiValidationError) writes.get(1).getError()).getStatusCode());
src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java (3)

498-519: Preserve HTTP metadata when returning synthesized per-tuple results

Here the API response is ignored and a synthetic ClientWriteResponse is returned. Consider preserving statusCode, headers, and raw response for observability and debugging.

If you add the constructor suggested in ClientWriteResponse, this block can be adjusted to:

return call(() -> api.write(storeId, body, overrides)).thenApply(apiResponse -> {
    // build writeResponses/deleteResponses as you already do...
    return new ClientWriteResponse(
        apiResponse.getStatusCode(),
        apiResponse.getHeaders(),
        apiResponse.getRawResponse(),
        writeResponses,
        deleteResponses
    );
});

I can follow up with a PR-ready patch across both files if you’d like.


714-720: writeTuples: also consider propagating HTTP metadata

Similar to writeTransactions, this path discards headers/raw response. If you adopt the new constructor, you can carry metadata through while still returning per-tuple results.

Suggested change after adding the new constructor:

return call(() -> api.write(storeId, body, overrides)).thenApply(apiResponse -> {
    List<ClientWriteSingleResponse> writeResponses = tupleKeys.stream()
        .map(tuple -> new ClientWriteSingleResponse(tuple.asTupleKey(), ClientWriteStatus.SUCCESS))
        .collect(Collectors.toList());
    return new ClientWriteResponse(
        apiResponse.getStatusCode(),
        apiResponse.getHeaders(),
        apiResponse.getRawResponse(),
        writeResponses,
        List.of()
    );
});

754-765: deleteTuples: also consider propagating HTTP metadata

Same rationale as writeTransactions/writeTuples: keep status/headers/raw if possible.

Suggested change after adding the new constructor:

return call(() -> api.write(storeId, body, overrides)).thenApply(apiResponse -> {
    List<ClientWriteSingleResponse> deleteResponses = tupleKeys.stream()
        .map(tuple -> new ClientWriteSingleResponse(
            new TupleKey().user(tuple.getUser()).relation(tuple.getRelation())._object(tuple.getObject()),
            ClientWriteStatus.SUCCESS))
        .collect(Collectors.toList());
    return new ClientWriteResponse(
        apiResponse.getStatusCode(),
        apiResponse.getHeaders(),
        apiResponse.getRawResponse(),
        List.of(),
        deleteResponses
    );
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7de8899 and 6779068.

📒 Files selected for processing (15)
  • .openapi-generator/FILES (4 hunks)
  • example/example1/gradle/wrapper/gradle-wrapper.properties (1 hunks)
  • example/example1/src/main/java/dev/openfga/sdk/example/Example1.java (2 hunks)
  • gradle/wrapper/gradle-wrapper.properties (1 hunks)
  • settings.gradle (1 hunks)
  • src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java (2 hunks)
  • src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java (6 hunks)
  • src/main/java/dev/openfga/sdk/api/client/model/ClientWriteResponse.java (2 hunks)
  • src/main/java/dev/openfga/sdk/api/client/model/ClientWriteSingleResponse.java (1 hunks)
  • src/main/java/dev/openfga/sdk/api/client/model/ClientWriteStatus.java (1 hunks)
  • src/main/java/dev/openfga/sdk/telemetry/Metrics.java (2 hunks)
  • src/main/java/dev/openfga/sdk/util/ExponentialBackoff.java (3 hunks)
  • src/test-integration/java/dev/openfga/sdk/example/Example1.java (2 hunks)
  • src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java (6 hunks)
  • src/test/java/dev/openfga/sdk/util/ExponentialBackoffTest.java (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java (1)
src/main/java/dev/openfga/sdk/telemetry/Attributes.java (1)
  • Attributes (31-216)
src/test/java/dev/openfga/sdk/util/ExponentialBackoffTest.java (1)
src/main/java/dev/openfga/sdk/util/ExponentialBackoff.java (1)
  • ExponentialBackoff (27-91)
src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java (1)
src/main/java/dev/openfga/sdk/api/client/model/ClientWriteRequest.java (1)
  • ClientWriteRequest (17-46)
🔇 Additional comments (12)
settings.gradle (1)

1-6: LGTM: pluginManagement repositories configured.

Defining gradlePluginPortal() and mavenCentral() at the settings level is a solid move for reproducible plugin resolution.

src/main/java/dev/openfga/sdk/telemetry/Metrics.java (1)

17-17: Switch to GlobalOpenTelemetry is appropriate.

Using GlobalOpenTelemetry aligns with standard OTel initialization patterns and preserves no-op behavior when not configured.

src/main/java/dev/openfga/sdk/util/ExponentialBackoff.java (2)

17-17: Good improvement: use ThreadLocalRandom for jitter.

This avoids shared RNG contention and is safer in concurrent contexts.


43-44: LGTM: route public calculateDelay through ThreadLocalRandom.

Keeps default behavior fast and thread-safe while retaining the testable overload.

src/test/java/dev/openfga/sdk/util/ExponentialBackoffTest.java (1)

17-17: Good addition: JUnit 5 assertThrows import is correctly used

The static import aligns with the new exception tests and keeps the code concise.

src/main/java/dev/openfga/sdk/api/client/model/ClientWriteStatus.java (1)

15-18: Enum introduction looks good

The SUCCESS/FAILURE statuses are a clear and minimal API for per-tuple write results and match the new response model.

src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java (1)

128-130: Retry telemetry attribute correctly recorded for HTTP errors

Adding HTTP_REQUEST_RESEND_COUNT on HTTP retry paths makes retry telemetry consistent with network error retries and with the attribute added on successful responses.

src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java (2)

1162-1167: LGTM: Good asserts on per-tuple results in transactional path

The added checks validate the new ClientWriteResponse structure and tuple-level SUCCESS status as expected for transactional writes.


2009-2009: LGTM: Clarified stubbed response to include structured error payload

The updated WireMock stub improves realism for the error case.

src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java (3)

361-405: Javadoc clearly documents the new transactional vs non-transactional semantics

The mode-specific behavior, error handling, and caller responsibilities are well explained.


415-461: Javadoc duplication: consistent and helpful on the overload

The duplicated documentation on the overloaded write is consistent and improves usability.


521-547: Javadoc for non-transactional write is thorough

Clear articulation of chunking, error isolation, and ordering guarantees.

@jimmyjames jimmyjames marked this pull request as draft August 15, 2025 16:42
@jimmyjames jimmyjames marked this pull request as ready for review August 15, 2025 17:57
@codecov-commenter
Copy link

codecov-commenter commented Aug 15, 2025

Codecov Report

❌ Patch coverage is 78.74016% with 27 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.19%. Comparing base (7de8899) to head (52b0083).

Files with missing lines Patch % Lines
...java/dev/openfga/sdk/api/client/OpenFgaClient.java 80.43% 12 Missing and 6 partials ⚠️
...nfga/sdk/api/client/model/ClientWriteResponse.java 54.54% 3 Missing and 2 partials ⚠️
...dev/openfga/sdk/api/client/HttpRequestAttempt.java 20.00% 4 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #206      +/-   ##
============================================
+ Coverage     34.58%   35.19%   +0.60%     
- Complexity     1043     1071      +28     
============================================
  Files           185      187       +2     
  Lines          6980     7087     +107     
  Branches        790      803      +13     
============================================
+ Hits           2414     2494      +80     
- Misses         4463     4483      +20     
- Partials        103      110       +7     

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

@jimmyjames jimmyjames enabled auto-merge August 15, 2025 18:43
@jimmyjames jimmyjames added this pull request to the merge queue Aug 15, 2025
Merged via the queue into main with commit 36c22b4 Aug 15, 2025
25 checks passed
@jimmyjames jimmyjames deleted the chore/sync-gen branch August 15, 2025 19:03
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.

3 participants