Skip to content

Allow retry policies to handle client-side request timeouts#960

Open
dkropachev wants to merge 1 commit into
scylladb:scylla-4.xfrom
dkropachev:dk/issue-958-request-timeout-retry
Open

Allow retry policies to handle client-side request timeouts#960
dkropachev wants to merge 1 commit into
scylladb:scylla-4.xfrom
dkropachev:dk/issue-958-request-timeout-retry

Conversation

@dkropachev

Copy link
Copy Markdown

Fixes #958

Summary

  • add RetryPolicy.onRequestTimeoutVerdict(...) for client-side DriverTimeoutException decisions with resolved consistency, idempotence, and retry count
  • route CqlRequestHandler request-timeout handling through the retry policy; retry verdicts cancel timed-out in-flight callbacks and restart the request timeout for the retried request
  • keep DefaultRetryPolicy conservative by rethrowing; let ConsistencyDowngradingRetryPolicy retry idempotent request timeouts on the next node
  • update retry docs, changelog, Revapi metadata, and focused unit tests

Testing

  • JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 PATH=/usr/lib/jvm/java-17-openjdk-amd64/bin:$PATH mvn -pl core -am -DskipTests test-compile
  • JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 PATH=/usr/lib/jvm/java-17-openjdk-amd64/bin:$PATH mvn -pl core -am -Dtest=CqlRequestHandlerTest,DefaultRetryPolicyTest,ConsistencyDowngradingRetryPolicyTest -Dsurefire.failIfNoSpecifiedTests=false test
  • JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 PATH=/usr/lib/jvm/java-17-openjdk-amd64/bin:$PATH mvn -pl core -am -DskipTests -DskipITs verify

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dkropachev, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b2adbe6b-45df-45b6-9a3c-f90dc818ce22

📥 Commits

Reviewing files that changed from the base of the PR and between e90312d and 8df5122.

📒 Files selected for processing (12)
  • changelog/README.md
  • core/revapi.json
  • core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryPolicy.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/ConsistencyDowngradingRetryPolicyTest.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/DefaultRetryPolicyTest.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java
  • core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java
  • core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java
  • manual/core/retries/README.md
📝 Walkthrough

Walkthrough

The retry API now exposes onRequestTimeoutVerdict(...) for client-side DriverTimeoutException failures. CqlRequestHandler invokes this hook with resolved consistency and idempotence information, processes retry verdicts, updates timeout metrics, restarts timeout scheduling when retrying, and suppresses stale executions. The default policy rethrows, while ConsistencyDowngradingRetryPolicy retries idempotent first attempts on the next host. Tests and documentation cover the behavior.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant CqlRequestHandler
  participant RetryPolicy
  participant Node
  Client->>CqlRequestHandler: submit statement
  CqlRequestHandler->>Node: send request
  CqlRequestHandler->>RetryPolicy: report DriverTimeoutException
  RetryPolicy-->>CqlRequestHandler: return RetryVerdict
  CqlRequestHandler->>Node: retry on next host when permitted
  CqlRequestHandler-->>Client: complete result or timeout error
Loading

Possibly related PRs

  • scylladb/java-driver#959: Adds a closely related client-side request-timeout retry-policy callback and associated handler, policy, test, and documentation changes.

Suggested reviewers: nikagra

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding retry-policy handling for client-side request timeouts.
Description check ✅ Passed The description is directly related to the code changes and matches the PR's stated goals and tests.
Linked Issues check ✅ Passed The PR meets #958 by adding a request-timeout retry hook, preserving default rethrow behavior, and covering retry and no-retry cases with docs.
Out of Scope Changes check ✅ Passed The remaining documentation, metadata, and handler refactors support the timeout-retry feature and appear in scope.

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java`:
- Around line 322-334: Update CqlRequestHandler.cancelTimedOutCallbacks and the
corresponding callback-registration path so timeout cancellation and new
callback registration are synchronized or guarded by a timeout generation/state
check. Reject and cancel callbacks created from stale executions after
cancellation, preventing them from running beside the retry; preserve
activeExecutionsCount accuracy when such callbacks are rejected.
- Around line 270-275: The callback-null branch in
CqlRequestHandler.processRequestTimeout currently fails pre-dispatch timeouts
without consulting the retry policy. Preserve or establish the request context
needed by retry handling, and route this path through the same
RetryPolicy.onRequestTimeoutVerdict flow used for in-flight callbacks, allowing
the policy to retry or rethrow instead of calling setFinalError directly.

In
`@core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java`:
- Around line 277-295: Update onRequestTimeoutVerdict so an idempotent request
returns RETRY_NEXT only when retryCount is zero; return RETHROW for subsequent
client-side timeouts while preserving the existing trace logging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f57070db-8130-41fc-8fb4-4a70a5a09822

📥 Commits

Reviewing files that changed from the base of the PR and between 3cafb2a and 0080f1c.

📒 Files selected for processing (12)
  • changelog/README.md
  • core/revapi.json
  • core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryPolicy.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/ConsistencyDowngradingRetryPolicyTest.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/DefaultRetryPolicyTest.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java
  • core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java
  • core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java
  • manual/core/retries/README.md

@dkropachev
dkropachev force-pushed the dk/issue-958-request-timeout-retry branch from 0080f1c to e90312d Compare July 16, 2026 12:50
@dkropachev

Copy link
Copy Markdown
Author

@autopilot review

@coderabbitai
coderabbitai Bot requested a review from nikagra July 16, 2026 12:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java (2)

307-310: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert that dispatch remains blocked until the throttler releases it.

An incorrect immediate dispatch could receive node1’s response before onThrottleReady, yet the final success assertion would still pass.

Proposed assertion
       CapturedTimeout requestTimeout = harness.nextScheduledTimeout();
       requestTimeout.task().run(requestTimeout);
 
+      assertThat(resultSetFuture.toCompletableFuture()).isNotDone();
       throttledCaptor.getValue().onThrottleReady(true);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java`
around lines 307 - 310, Update the test flow around
throttledCaptor.getValue().onThrottleReady(true) to assert that no request
dispatch or response occurs after the scheduled timeout runs but before the
throttler is released. Then retain the release call and existing success
assertions to verify dispatch proceeds only after onThrottleReady.

220-221: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise the restarted timeout and incremented retry count.

Every retry currently succeeds immediately, so these tests would still pass if the retry did not schedule a fresh timeout or propagated retry count 0 again. Add a hanging second attempt, fire its captured timeout, and verify the policy receives retry count 1.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java`
around lines 220 - 221, Extend the retry test around
requestTimeout.task().run(requestTimeout) to make the second attempt hang
instead of succeeding immediately, capture and fire its newly scheduled timeout,
and assert the retry policy receives retry count 1. Preserve the existing
first-attempt timeout flow while ensuring the test exercises both rescheduling
and incremented retry state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java`:
- Around line 319-321: Update the IGNORE handling in CqlRequestHandler,
including the corresponding path around the alternate reported lines, so
RequestTracker.onSuccess is never invoked with a null coordinator. Skip the
success callback when no coordinator is available, or preserve and pass a valid
coordinator context while keeping the existing timeout cancellation and
final-result behavior.
- Around line 156-160: Update the pre-dispatch timeout handling and
onThrottleReady coordination in CqlRequestHandler to synchronize one immutable
phase/state snapshot under the existing lock, rather than independently checking
callback, started, preDispatchStatement, and preDispatchRetryCount. Add an
explicit state indicating that throttle dispatch is still pending, and allow the
timeout transition only from that state; atomically clear or replace the pending
request and retry count so onThrottleReady cannot dispatch the old request
concurrently with the retry.
- Around line 818-819: Update the catch block in the overload that has the
execution parameter to pass that existing execution value to setFinalError
instead of -1. Preserve the current error and node arguments while retaining the
correct execution metadata when finalization fails.

---

Nitpick comments:
In
`@core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java`:
- Around line 307-310: Update the test flow around
throttledCaptor.getValue().onThrottleReady(true) to assert that no request
dispatch or response occurs after the scheduled timeout runs but before the
throttler is released. Then retain the release call and existing success
assertions to verify dispatch proceeds only after onThrottleReady.
- Around line 220-221: Extend the retry test around
requestTimeout.task().run(requestTimeout) to make the second attempt hang
instead of succeeding immediately, capture and fire its newly scheduled timeout,
and assert the retry policy receives retry count 1. Preserve the existing
first-attempt timeout flow while ensuring the test exercises both rescheduling
and incremented retry state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ad75072-bdf6-42ef-a8ba-d910e649c659

📥 Commits

Reviewing files that changed from the base of the PR and between 0080f1c and e90312d.

📒 Files selected for processing (12)
  • changelog/README.md
  • core/revapi.json
  • core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryPolicy.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandler.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/ConsistencyDowngradingRetryPolicyTest.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/DefaultRetryPolicyTest.java
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java
  • core/src/test/java/com/datastax/oss/driver/internal/core/cql/CqlRequestHandlerTest.java
  • core/src/test/java/com/datastax/oss/driver/internal/core/cql/RequestHandlerTestHarness.java
  • manual/core/retries/README.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • changelog/README.md
  • core/src/test/java/com/datastax/oss/driver/api/core/retry/RetryPolicyTestBase.java
  • core/src/main/java/com/datastax/oss/driver/api/core/retry/RetryPolicy.java
  • manual/core/retries/README.md
  • core/src/main/java/com/datastax/oss/driver/internal/core/retry/ConsistencyDowngradingRetryPolicy.java
  • core/src/main/java/com/datastax/oss/driver/internal/core/retry/DefaultRetryPolicy.java

@dkropachev
dkropachev force-pushed the dk/issue-958-request-timeout-retry branch from e90312d to f74f8dc Compare July 16, 2026 14:10
@dkropachev
dkropachev force-pushed the dk/issue-958-request-timeout-retry branch from f74f8dc to 8df5122 Compare July 16, 2026 14:10
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.

Allow retry policy to handle client-side DriverTimeoutException

1 participant