Conversation
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiter.java
Outdated
Show resolved
Hide resolved
| * Returns a {@link RetryLimiter} which limits the number of concurrent retry requests. | ||
| * This limiter does not consider {@link RetryDecision#permits()} when limiting retries. | ||
| */ | ||
| static RetryLimiter concurrencyLimiting(long maxRequests) { |
There was a problem hiding this comment.
Optional) Would it be useful to support rateLimiting by default?
There was a problem hiding this comment.
I forgot to leave a comment on this - the RetryLimiter API doesn't go well with guava's RateLimiter as there is no way to determine if a the state should be rate-limited at a given time.
I'd like to revisit this later on unless I'm missing something/you have a better idea.
There was a problem hiding this comment.
I think using a rate limiter is also an important way to control retries, but we don’t need to implement it now. We can consider it later as a separate issue.
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiters.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiters.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/TokenBasedRetryLimiter.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/TokenBasedRetryLimiter.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiter.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiter.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/RetryingClient.java
Outdated
Show resolved
Hide resolved
| if (permits > 0) { | ||
| if (currentCount == 0) { | ||
| break; | ||
| } | ||
| newCount = Math.max(currentCount - THREE_DECIMAL_PLACES_SCALE_UP, 0); |
There was a problem hiding this comment.
The Javadoc says
each positive {@link RetryDecision#permits()} will increment available tokens by {@code tokenRatio}
Which is different from the actual logic.
Does the permit always -1, 0, 1?
I'm asking because this logic doesn't take into account the permit numbers, so I was wondering if we could use more specific names than 'permit'.
There was a problem hiding this comment.
I've generalized tokenBased. Although users who prefer gRPC-style retry limiting will need to add a little more logic, the probably makes more sense for general users.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6409 +/- ##
============================================
- Coverage 74.46% 74.19% -0.27%
- Complexity 22234 23306 +1072
============================================
Files 1963 2094 +131
Lines 82437 87069 +4632
Branches 10764 11446 +682
============================================
+ Hits 61385 64602 +3217
- Misses 15918 17013 +1095
- Partials 5134 5454 +320 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
core/src/main/java/com/linecorp/armeria/client/retry/TokenBasedRetryLimiter.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/ConcurrencyBasedRetryLimiter.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/ConcurrencyBasedRetryLimiter.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.java
Show resolved
Hide resolved
|
Why is this PR rescheduled to 1.35.0? I was wondering if there is remaining issues in this PR that I missed. |
There are no remaining issues, I'm just more concerned of releasing on schedule at the moment. |
WalkthroughA retry limiting feature is introduced supporting both concurrency-based and token-based retry throttling. The RetryLimiter interface provides two factory methods for creating limiters, with implementations enforcing retry constraints. RetryDecision now carries a permits value. Retry configuration propagates the limiter through execution paths, and retry clients check permissions before attempting retries, notifying limiters of decisions. Changes
Sequence DiagramsequenceDiagram
participant Client
participant RetryingClient
participant RetryLimiter
participant Upstream
rect rgb(200, 220, 255)
Note over Client,Upstream: Initial Request
Client->>RetryingClient: execute(request)
RetryingClient->>Upstream: send request
Upstream-->>RetryingClient: response/error
end
rect rgb(255, 220, 200)
Note over RetryingClient,RetryLimiter: Retry Attempt Decision
alt Not First Attempt
RetryingClient->>RetryLimiter: shouldRetry(ctx)
alt Permission Denied
RetryLimiter-->>RetryingClient: false
RetryingClient-->>Client: RetryLimitedException
else Permission Granted
RetryLimiter-->>RetryingClient: true
RetryingClient->>Upstream: send retry request
Upstream-->>RetryingClient: response
end
end
end
rect rgb(220, 255, 220)
Note over RetryingClient,RetryLimiter: Decision Notification
alt Retry Decision Made
RetryingClient->>RetryingClient: evaluate retry decision
RetryingClient->>RetryLimiter: handleDecision(ctx, decision)
Note over RetryLimiter: Update permits/tokens
end
end
RetryingClient-->>Client: final response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
core/src/main/java/com/linecorp/armeria/client/retry/RetryingRpcClient.java (1)
202-205: Remove redundantmappedRetryConfigcall.
mappedRetryConfig(ctx)is already called at line 174 and stored inconfig. The second call at line 202 is redundant and can be replaced with the existingconfigvariable.- final RetryConfig<RpcResponse> retryConfig = mappedRetryConfig(ctx); final RetryRuleWithContent<RpcResponse> retryRule = - retryConfig.needsContentInRule() ? - retryConfig.retryRuleWithContent() : retryConfig.fromRetryRule(); + config.needsContentInRule() ? + config.retryRuleWithContent() : config.fromRetryRule();core/src/test/java/com/linecorp/armeria/client/retry/RetryLimiterIntegrationTest.java (1)
105-141: LGTM!The test validates that exceptions thrown by a
RetryLimiterare gracefully handled and converted toRetryLimitedException. The counter value of 1 confirms only the initial request executes.Minor nit: The
maxRequestsvariable on line 112 is unused and could be removed for clarity.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
core/src/main/java/com/linecorp/armeria/client/retry/ConcurrencyBasedRetryLimiter.java(1 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryConfig.java(4 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryConfigBuilder.java(4 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryDecision.java(3 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.java(1 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiter.java(1 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiters.java(1 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryRuleBuilder.java(1 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryRuleWithContentBuilder.java(1 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryingClient.java(5 hunks)core/src/main/java/com/linecorp/armeria/client/retry/RetryingRpcClient.java(3 hunks)core/src/main/java/com/linecorp/armeria/client/retry/TokenBasedRetryLimiter.java(1 hunks)core/src/test/java/com/linecorp/armeria/client/retry/RetryLimiterIntegrationTest.java(1 hunks)core/src/test/java/com/linecorp/armeria/client/retry/RetryLimiterTest.java(1 hunks)thrift/thrift0.13/src/test/java/com/linecorp/armeria/client/thrift/RpcRetryLimiterTest.java(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.java
⚙️ CodeRabbit configuration file
**/*.java: - The primary coding conventions and style guide for this project are defined insite/src/pages/community/developer-guide.mdx. Please strictly adhere to this file as the ultimate source of truth for all style and convention-related feedback.2. Specific check for
@UnstableApi
- Review all newly added public classes and methods to ensure they have the
@UnstableApiannotation.- However, this annotation is NOT required under the following conditions:
- If the class or method is located in a package containing
.internal.- If a public method is part of a class that is already annotated with
@UnstableApi.
Files:
core/src/main/java/com/linecorp/armeria/client/retry/RetryRuleWithContentBuilder.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryLimiters.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryConfigBuilder.javacore/src/test/java/com/linecorp/armeria/client/retry/RetryLimiterTest.javacore/src/main/java/com/linecorp/armeria/client/retry/ConcurrencyBasedRetryLimiter.javacore/src/main/java/com/linecorp/armeria/client/retry/TokenBasedRetryLimiter.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryLimiter.javacore/src/test/java/com/linecorp/armeria/client/retry/RetryLimiterIntegrationTest.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryConfig.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryingClient.javathrift/thrift0.13/src/test/java/com/linecorp/armeria/client/thrift/RpcRetryLimiterTest.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryingRpcClient.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryRuleBuilder.javacore/src/main/java/com/linecorp/armeria/client/retry/RetryDecision.java
🧬 Code graph analysis (5)
core/src/main/java/com/linecorp/armeria/client/retry/RetryConfigBuilder.java (1)
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiters.java (2)
RetryLimiters(24-65)AlwaysRetryLimiter(56-64)
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.java (1)
core/src/main/java/com/linecorp/armeria/common/Flags.java (1)
Flags(106-1897)
core/src/main/java/com/linecorp/armeria/client/retry/RetryingClient.java (1)
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.java (1)
RetryLimitedException(24-44)
thrift/thrift0.13/src/test/java/com/linecorp/armeria/client/thrift/RpcRetryLimiterTest.java (5)
core/src/main/java/com/linecorp/armeria/client/UnprocessedRequestException.java (1)
UnprocessedRequestException(32-70)core/src/main/java/com/linecorp/armeria/client/retry/RetryConfig.java (1)
RetryConfig(35-251)core/src/main/java/com/linecorp/armeria/client/retry/RetryDecision.java (1)
RetryDecision(30-117)core/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.java (1)
RetryLimitedException(24-44)core/src/main/java/com/linecorp/armeria/client/retry/RetryingRpcClient.java (1)
RetryingRpcClient(41-254)
core/src/main/java/com/linecorp/armeria/client/retry/RetryingRpcClient.java (2)
core/src/main/java/com/linecorp/armeria/client/UnprocessedRequestException.java (1)
UnprocessedRequestException(32-70)core/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.java (1)
RetryLimitedException(24-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: build-macos-latest-jdk-21
- GitHub Check: build-ubicloud-standard-16-jdk-17-leak
- GitHub Check: build-windows-latest-jdk-21
- GitHub Check: build-ubicloud-standard-16-jdk-11
- GitHub Check: build-ubicloud-standard-16-jdk-17-min-java-11
- GitHub Check: build-ubicloud-standard-16-jdk-8
- GitHub Check: build-ubicloud-standard-16-jdk-17-min-java-17-coverage
- GitHub Check: flaky-tests
- GitHub Check: build-ubicloud-standard-16-jdk-21-snapshot-blockhound
- GitHub Check: lint
- GitHub Check: site
- GitHub Check: Kubernetes Chaos test
- GitHub Check: Summary
🔇 Additional comments (37)
core/src/main/java/com/linecorp/armeria/client/retry/RetryRuleWithContentBuilder.java (1)
66-77: LGTM!The visibility change to
publicand the updated conditiondecision.backoff() != nullare appropriate. The backoff-null check is more direct and aligns with the retry flow semantics.core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiters.java (2)
26-54: LGTM!
CatchingRetryLimiterprovides appropriate defensive wrapping with fail-safe behavior (returningfalseon exception to prevent retries when limiter state is uncertain). Logging warnings helps with debugging.
56-64: LGTM!
AlwaysRetryLimiterprovides a clean no-op default implementation for cases where retry limiting is not configured.core/src/main/java/com/linecorp/armeria/client/retry/RetryingRpcClient.java (2)
174-182: LGTM!The retry limiter check is correctly placed for non-initial attempts, and the exception wrapping with
UnprocessedRequestException.of(RetryLimitedException.of())follows the established pattern for unprocessed request errors.
210-212: LGTM!The
handleDecisioncall correctly notifies the limiter after a retry decision is made, enabling token/concurrency accounting.core/src/main/java/com/linecorp/armeria/client/retry/RetryConfigBuilder.java (2)
130-139: LGTM!The
retryLimiteris correctly wired through both build paths (withRetryRuleandRetryRuleWithContent).
116-123: Unable to verify@UnstableApiannotation coverage due to repository access issues.The automated verification cannot be completed as the repository cannot be cloned. To determine if this public method requires the
@UnstableApiannotation, manually verify whetherRetryConfigBuilderhas the annotation at the class level:
- If
@UnstableApiis present on the class declaration, the method is compliant.- If
@UnstableApiis absent at class level, the methodretryLimiter(RetryLimiter)at lines 116-123 must be annotated with@UnstableApi(per coding guidelines for public methods not in.internalpackages).core/src/main/java/com/linecorp/armeria/client/retry/TokenBasedRetryLimiter.java (3)
41-48: LGTM!Constructor validation and initialization are correct. Starting
tokenCountatmaxTokensensures the limiter begins with full capacity.
62-68: LGTM on the CAS loop implementation.The compare-and-set loop with clamping to
[0, maxTokens]correctly handles concurrent updates without locks.
55-69: Unable to verify the precision loss concern due to repository access issues and incomplete web documentation.The repository clone is failing, preventing direct inspection of the
RetryDecisioninterface definition andpermits()method documentation. Web searches did not yield specific documentation about thepermits()contract or whether fractional values are semantically meaningful in this context.The concern itself is technically valid—casting
doubletointdoes truncate fractional values—but without access to:
- The
RetryDecision#permits()javadoc and contract- Design documentation explaining whether fractional permits are meaningful
- Usage patterns and tests showing expected behavior
it cannot be determined whether this truncation is intentional or problematic. A developer with repository access should:
- Review the
RetryDecisioninterface to understand the semantics ofpermits()- Check if fractional permits are ever produced in practice
- Verify if truncation aligns with the retry token model's design
thrift/thrift0.13/src/test/java/com/linecorp/armeria/client/thrift/RpcRetryLimiterTest.java (1)
44-49: Verify token consumption aligns with test expectations.The
RetryDecision.retry(fixed)doesn't specify a permits value, which likely defaults to 0. With a token-based limiter configured astokenBased(3, 1), the tokens might not be consumed as expected since the default permits may not trigger token deduction. Consider explicitly specifying permits in theRetryDecisionto ensure the test accurately validates token-based limiting behavior:final RetryRule retryRule = RetryRule.builder() .onException() - .build(RetryDecision.retry(fixed)); + .build(RetryDecision.retry(fixed, 1));core/src/main/java/com/linecorp/armeria/client/retry/RetryRuleBuilder.java (1)
66-81: LGTM!The visibility change to
publicenables external usage viaRetryDecisionfor the newRetryLimiterfeature. The guard condition refinement to checkdecision.backoff() != nullis semantically correct sincenoRetrydecisions have a null backoff.core/src/test/java/com/linecorp/armeria/client/retry/RetryLimiterIntegrationTest.java (2)
36-71: LGTM!The test correctly validates concurrency-based retry limiting. The logic ensures 3 concurrent retries hold slots (via streaming responses), and the 4th request's retry is blocked. The counter assertion of
maxRequests * 2 + 1 = 7correctly accounts for all initial attempts plus retries.
73-103: LGTM!The test accurately emulates gRPC-style retry throttling with token-based limiting. The counter value of 2 correctly reflects the token consumption pattern: initial request plus one retry before tokens fall to the threshold.
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimiter.java (1)
42-80: LGTM!The interface is well-designed with clear Javadoc, appropriate
@UnstableApiannotation, and sensible defaults. The factory methods provide convenient access to the built-in limiter implementations.core/src/main/java/com/linecorp/armeria/client/retry/ConcurrencyBasedRetryLimiter.java (1)
37-46: LGTM!The concurrency control logic is thread-safe. The atomic increment-check-decrement pattern correctly handles race conditions, and the completion callback ensures proper cleanup when retries complete.
core/src/test/java/com/linecorp/armeria/client/retry/RetryLimiterTest.java (8)
30-37: LGTM!Test correctly verifies that multiple retry attempts are allowed when under the concurrency limit.
39-51: LGTM!Good test for verifying concurrency limiting blocks excess retries and correctly handles cancellation to free up permits.
53-66: LGTM!Correctly verifies that concurrency-based limiter ignores
handleDecisioncalls since it tracks active retries rather than token consumption.
68-74: LGTM!Simple verification that token-based limiter allows retries when tokens are available.
76-88: LGTM!Test correctly verifies that token-based limiter blocks retries when tokens are exhausted after consuming permits via
handleDecision.
90-107: LGTM!Correctly verifies that negative permit values in
handleDecisionreplenish tokens, allowing subsequent retries.
109-119: LGTM!Correctly verifies that zero-permit decisions don't consume tokens, allowing unlimited retries in that scenario.
121-123: LGTM!Simple helper method for creating test contexts.
core/src/main/java/com/linecorp/armeria/client/retry/RetryDecision.java (5)
63-68: Consider adding@UnstableApiannotation to the new public method.Same as the
retry(Backoff, double)method - this new public API should have@UnstableApiif the class doesn't already have it.
92-100: Consider adding@UnstableApiannotation to the new public method.The
permits()accessor is a new public API that exposes the permits value to users. Consider adding@UnstableApiannotation.
102-116: LGTM!Good use of
MoreObjects.ToStringHelperfor structured toString output. The type detection logic correctly handles NEXT, RETRY, and NO_RETRY cases.
32-42: LGTM!Good default behavior - existing
retry(Backoff)calls now transparently use permits=1, maintaining backward compatibility while supporting the new limiter functionality.
44-53: I apologize, but I'm unable to access the repository to verify whether theRetryDecisionclass already has the@UnstableApiannotation. The repository clone is failing consistently.However, based on the information provided:
Verify whether the
RetryDecisionclass already has@UnstableApiannotation at the class level.Per the coding guidelines, the new public method
retry(Backoff backoff, double permits)requires@UnstableApionly if:
- The class does NOT already have
@UnstableApi, AND- The package does NOT contain
.internalSince the package is
com.linecorp.armeria.client.retry(which does not contain.internal), the annotation is needed on the method unless the class itself is already annotated.core/src/main/java/com/linecorp/armeria/client/retry/RetryConfig.java (3)
115-115: Defensive wrapping withCatchingRetryLimiteris a good pattern.Wrapping user-provided limiters ensures that exceptions in custom limiter implementations don't break the retry flow. This is a good defensive coding practice.
152-156: LGTM!Correctly preserves the
retryLimiterwhen converting to builder, ensuring round-trip configuration works as expected.
205-210: I'm encountering technical issues accessing the repository directly. However, I can work with the information provided in the coding guidelines and the review context.Based on the coding guidelines provided:
- New public methods require
@UnstableApiannotation unless the containing class already has it- The package
com.linecorp.armeria.client.retrydoes not contain.internal, so that exception doesn't applyThe review comment correctly identifies that the
retryLimiter()public accessor needs@UnstableApiannotation if theRetryConfigclass itself doesn't already have it.Since I cannot directly verify the current state of the
RetryConfigclass annotation due to system constraints, I need to flag this for manual verification:Add
@UnstableApiannotation to theretryLimiter()public method unless theRetryConfigclass is already annotated with@UnstableApi.Per the coding guidelines, new public API additions must have the
@UnstableApiannotation unless the containing class already provides it. Verify the class-level annotations onRetryConfigto determine if this method-level annotation is necessary.core/src/main/java/com/linecorp/armeria/client/retry/RetryingClient.java (5)
315-322: LGTM - Good placement of retry limiter check.The limiter check is correctly placed:
- After creating the derived context (so limiter has access to request info)
- Before executing the actual request (to prevent unnecessary work)
- Only for non-initial attempts (first attempt should always proceed)
The
RetryLimitedExceptionfailure handling is appropriate.
533-540: LGTM!The
handleDecisioncall is correctly guarded by null check and placed before checking the backoff, ensuring the limiter is notified of all decisions (both retry and no-retry).
363-378: LGTM!Config is correctly threaded through
handleResponseWithoutContenttohandleRetryDecision.
419-426: LGTM!Config is correctly propagated through the streaming response handling path.
458-464: LGTM!Config is correctly propagated through the aggregated response handling path with content-based retry rules.
| /** | ||
| * An exception thrown when a retry is limited by a {@link RetryLimiter}. | ||
| */ | ||
| public final class RetryLimitedException extends RuntimeException { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Missing @UnstableApi annotation on new public class.
Per coding guidelines, newly added public classes should have the @UnstableApi annotation.
+import com.linecorp.armeria.common.annotation.UnstableApi;
+
/**
* An exception thrown when a retry is limited by a {@link RetryLimiter}.
*/
+@UnstableApi
public final class RetryLimitedException extends RuntimeException {🤖 Prompt for AI Agents
In
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.java
around line 24, the new public class lacks the required @UnstableApi annotation;
add the annotation above the class declaration and import the annotation
(com.linecorp.armeria.common.annotation.UnstableApi) so the class is marked
unstable per coding guidelines.
| private RetryLimitedException(boolean enableSuppression) { | ||
| super(null, null, enableSuppression, isSampled()); | ||
| } |
There was a problem hiding this comment.
Potential bug: INSTANCE may retain stack trace unintentionally.
When INSTANCE is created at static initialization, isSampled() is called for writableStackTrace. If the sampler happens to return true at that moment, INSTANCE will have a stack trace captured, defeating the purpose of the lightweight singleton.
The writableStackTrace parameter should use enableSuppression directly to ensure INSTANCE never captures a stack trace.
private RetryLimitedException(boolean enableSuppression) {
- super(null, null, enableSuppression, isSampled());
+ super(null, null, enableSuppression, enableSuppression);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private RetryLimitedException(boolean enableSuppression) { | |
| super(null, null, enableSuppression, isSampled()); | |
| } | |
| private RetryLimitedException(boolean enableSuppression) { | |
| super(null, null, enableSuppression, enableSuppression); | |
| } |
🤖 Prompt for AI Agents
In
core/src/main/java/com/linecorp/armeria/client/retry/RetryLimitedException.java
around lines 37 to 39, the private constructor currently passes isSampled() as
the writableStackTrace argument which can cause the static INSTANCE to capture a
stack trace; change the constructor call to pass enableSuppression for the
writableStackTrace parameter instead of isSampled(), so the INSTANCE never
creates a stack trace while preserving suppression behavior.
Motivation: This changeset attempts to solve the same problem as line#6318. Retry limiting is a concept which limits the number of retries in case a system undergoes a prolonged period of service degradation. gRPC offers a [token-based](https://github.com/grpc/proposal/blob/master/A6-client-retries.md#throttling-retry-attempts-and-hedged-rpcs) configuration which limits retries depending on certain predicates, whereas envoy offers a simple [concurrency limiting configuration](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/circuit_breaker.proto#envoy-v3-api-msg-config-cluster-v3-circuitbreakers-thresholds-retrybudget) based on the number of active retries. To support token-based retry limiters, I propose that `RetryDecision#permits` is added as metadata which could signal to `RetryLimiter` whether retries should be further made. This could be useful for systems behind load balancers, as the load balancer may return certain status codes depending on the health upstream. To support simple concurrency-based retry limiters, I propose that a `RetryLimiter#shouldRetry` method is called right before a retry is executed. Modifications: - Introduced `RetryLimiter` which acts as an extension to dynamically limit retries. - `RetryLimiter#shouldRetry` decides whether a retry should be executed - `RetryLimiter#handleDecision` is invoked when a `RetryDecision` is made. `RetryDecision#permits` may be used to update the internal state and decide whether retries should be allowed. - Added `RetryDecision#permits` - Added APIs so users can set `RetryLimiter` to `RetryConfig` Result: - Users can specify `RetryLimiter` to limit retry requests. - Closes line#6282 <!-- Visit this URL to learn more about how to write a pull request description: https://armeria.dev/community/developer-guide#how-to-write-pull-request-description -->
Motivation:
This changeset attempts to solve the same problem as #6318.
Retry limiting is a concept which limits the number of retries in case a system undergoes a prolonged period of service degradation.
gRPC offers a token-based configuration which limits retries depending on certain predicates, whereas envoy offers a simple concurrency limiting configuration based on the number of active retries.
To support token-based retry limiters, I propose that
RetryDecision#permitsis added as metadata which could signal toRetryLimiterwhether retries should be further made. This could be useful for systems behind load balancers, as the load balancer may return certain status codes depending on the health upstream.To support simple concurrency-based retry limiters, I propose that a
RetryLimiter#shouldRetrymethod is called right before a retry is executed.Modifications:
RetryLimiterwhich acts as an extension to dynamically limit retries.RetryLimiter#shouldRetrydecides whether a retry should be executedRetryLimiter#handleDecisionis invoked when aRetryDecisionis made.RetryDecision#permitsmay be used to update the internal state and decide whether retries should be allowed.RetryDecision#permitsRetryLimitertoRetryConfigResult:
RetryLimiterto limit retry requests.