Skip to content

Commit

Permalink
docs: touchups for resilience features (#3106)
Browse files Browse the repository at this point in the history
Motivation:

There are a few things that can be cleaned up.

Modifications:

- List examples.
- Await server shutdown for server examples.
- Drop redundant example.
  • Loading branch information
bryce-anderson authored Nov 14, 2024
1 parent 8d30706 commit 799574e
Show file tree
Hide file tree
Showing 14 changed files with 106 additions and 66 deletions.
25 changes: 24 additions & 1 deletion servicetalk-examples/docs/modules/ROOT/pages/http/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,33 @@ Async `Hello World` example that demonstrates how retry can be requested for a s
Async `Hello World` example that demonstrates how retry can be requested for a multi-address client.

[#TrafficResiliency]
= Traffic Resiliency
== Traffic Resiliency

Some examples that use the traffic resiliency features.

- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/GradientObservabilityExample.java[GradientObservabilityExample] -
An example that demonstrates using the observer pattern to instrument the gradient capacity limiter.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceClientBreakersExample.java[TrafficResilienceClientBreakersExample] -
A client that uses request metadata to select the correct circuit breaker.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceClientPeerRejectionsExample.java[TrafficResilienceClientPeerRejectionsExample] -
A client which configures what constitutes a rejection based on response status code.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceClientPeerRejectionsPassthroughExample.java[TrafficResilienceClientPeerRejectionsPassthroughExample] -
A client which configures which responses will affect the capacity limiter but still pass through to the underlying
client.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceClientPeerRejectionsRetryExample.java[TrafficResilienceClientPeerRejectionsRetryExample] -
A client which configures the resilience filters to signal an appropriate delay to the retry filter.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceServerClassificationExample.java[TrafficResilienceServerClassificationExample] -
A server that specifies the importance of requests based on the request metadata.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceServerExample.java[TrafficResilienceServerExample] -
A server that uses the dynamic gradient capacity limiter.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceServerPartitionExample.java[TrafficResilienceServerPartitionExample] -
A server that uses two separate capacity limiters, selected based on request metadata.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceServerQuotasExample.java[TrafficResilienceServerQuotasExample] -
A server that uses fixed capacity limiters based on the customer identity, as determined by the request metadata.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceServerStopAcceptingExample.java[TrafficResilienceServerStopAcceptingExample] -
A server that stops accepting new connections when it reaches its rejection threshold.
- link:{source-root}/servicetalk-examples/http/traffic-resilience/src/main/java/io/servicetalk/examples/http/traffic/resilience/TrafficResilienceServerTerminalsExample.java[TrafficResilienceServerTerminalsExample] -
An example that demonstrates custom handling of tickets on error conditions.

[#HTTP2]
== HTTP/2
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

import static io.servicetalk.capacity.limiter.api.CapacityLimiters.dynamicGradientOptimizeForThroughput;

/**
* An example that demonstrates using the observer pattern to instrument the gradient capacity limiter.
*/
public final class GradientObservabilityExample {

@SuppressWarnings({"UseOfSystemOutOrSystemErr", "PMD.SystemPrintln"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,40 @@
import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.circuit.breaker.api.CircuitBreaker;
import io.servicetalk.circuit.breaker.resilience4j.Resilience4jAdapters;
import io.servicetalk.http.api.HttpClient;
import io.servicetalk.http.api.BlockingHttpClient;
import io.servicetalk.http.netty.HttpClients;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpClientFilter;

/**
* An example demonstrating the selection of the appropriate circuit breaker based on request metadata.
*/
public final class TrafficResilienceClientBreakersExample {
public static void main(String[] args) throws Exception {
final TrafficResilienceHttpClientFilter resilienceFilter =
new TrafficResilienceHttpClientFilter.Builder(() -> CapacityLimiters.dynamicGradient().build())
.circuitBreakerPartitions(() -> {
final CircuitBreaker breakerForPathA = Resilience4jAdapters.fromCircuitBreaker(
io.github.resilience4j.circuitbreaker.CircuitBreaker.ofDefaults("example-a"));
final CircuitBreaker breakerForPathB = Resilience4jAdapters.fromCircuitBreaker(
final CircuitBreaker breakerForNonAPaths = Resilience4jAdapters.fromCircuitBreaker(
io.github.resilience4j.circuitbreaker.CircuitBreaker.ofDefaults("example-b"));

return requestMetaData -> {
if ("/A".equals(requestMetaData.requestTarget())) {
return breakerForPathA;
}
return breakerForPathB;
return breakerForNonAPaths;
};
})
.build();

try (HttpClient client = HttpClients.forSingleAddress("localhost", 8080)
try (BlockingHttpClient client = HttpClients.forSingleAddress("localhost", 8080)
.appendClientFilter(resilienceFilter)
.build()) {
// use client
.build()
.asBlockingClient()) {
// Will use breakerForPathA
client.request(client.get("/A"));
// Will use breakerForNonAPaths
client.request(client.get("/other"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.servicetalk.examples.http.traffic.resilience;

import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.http.api.BlockingHttpClient;
import io.servicetalk.http.netty.HttpClients;
import io.servicetalk.traffic.resilience.http.ClientPeerRejectionPolicy;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpClientFilter;
Expand All @@ -24,8 +25,11 @@
import static io.servicetalk.http.api.HttpResponseStatus.SERVICE_UNAVAILABLE;
import static io.servicetalk.http.api.HttpResponseStatus.TOO_MANY_REQUESTS;

/**
* An example demonstrating the configuration of what constitutes a rejection based on response status code.
*/
public final class TrafficResilienceClientPeerRejectionsExample {
public static void main(String[] args) {
public static void main(String[] args) throws Exception {
final TrafficResilienceHttpClientFilter resilienceFilter =
new TrafficResilienceHttpClientFilter.Builder(() -> CapacityLimiters.dynamicGradient().build())
.rejectionPolicy(ClientPeerRejectionPolicy.ofRejection(metaData ->
Expand All @@ -34,8 +38,10 @@ public static void main(String[] args) {
metaData.status().code() == SERVICE_UNAVAILABLE.code()))
.build();

HttpClients.forSingleAddress("localhost", 8080)
try (BlockingHttpClient client = HttpClients.forSingleAddress("localhost", 8080)
.appendClientFilter(resilienceFilter)
.build();
.build().asBlockingClient()) {
client.request(client.get("/foo"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.servicetalk.examples.http.traffic.resilience;

import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.http.api.BlockingHttpClient;
import io.servicetalk.http.netty.HttpClients;
import io.servicetalk.traffic.resilience.http.ClientPeerRejectionPolicy;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpClientFilter;
Expand All @@ -24,8 +25,12 @@
import static io.servicetalk.http.api.HttpResponseStatus.SERVICE_UNAVAILABLE;
import static io.servicetalk.http.api.HttpResponseStatus.TOO_MANY_REQUESTS;

/**
* A client which configures which responses will affect the capacity limiter but still pass through to the underlying
* client.
*/
public final class TrafficResilienceClientPeerRejectionsPassthroughExample {
public static void main(String[] args) {
public static void main(String[] args) throws Exception {
final TrafficResilienceHttpClientFilter resilienceFilter =
new TrafficResilienceHttpClientFilter.Builder(() -> CapacityLimiters.dynamicGradient().build())
.rejectionPolicy(ClientPeerRejectionPolicy.ofPassthrough(metaData ->
Expand All @@ -34,8 +39,11 @@ public static void main(String[] args) {
metaData.status().code() == SERVICE_UNAVAILABLE.code()))
.build();

HttpClients.forSingleAddress("localhost", 8080)
try (BlockingHttpClient client = HttpClients.forSingleAddress("localhost", 8080)
.appendClientFilter(resilienceFilter)
.build();
.build()
.asBlockingClient()) {
client.request(client.get("/foo"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.servicetalk.examples.http.traffic.resilience;

import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.http.api.BlockingHttpClient;
import io.servicetalk.http.netty.HttpClients;
import io.servicetalk.http.netty.RetryingHttpRequesterFilter;
import io.servicetalk.traffic.resilience.http.ClientPeerRejectionPolicy;
Expand All @@ -28,8 +29,11 @@
import static java.time.Duration.ofMillis;
import static java.time.Duration.ofSeconds;

/**
* A client which configures the resilience filters to signal an appropriate delay to the retry filter.
*/
public final class TrafficResilienceClientPeerRejectionsRetryExample {
public static void main(String[] args) {
public static void main(String[] args) throws Exception {
final TrafficResilienceHttpClientFilter resilienceFilter =
new TrafficResilienceHttpClientFilter.Builder(() -> CapacityLimiters.dynamicGradient().build())
.rejectionPolicy(ClientPeerRejectionPolicy.ofRejectionWithRetries(DEFAULT_CAPACITY_REJECTION_PREDICATE,
Expand All @@ -41,9 +45,12 @@ public static void main(String[] args) {
ofExponentialBackoffDeltaJitter(retry.delay(), ofMillis(500), ofSeconds(2), 2))
.build();

HttpClients.forSingleAddress("localhost", 8080)
try (BlockingHttpClient client = HttpClients.forSingleAddress("localhost", 8080)
.appendClientFilter(retryingHttpRequesterFilter)
.appendClientFilter(resilienceFilter)
.build();
.build()
.asBlockingClient()) {
client.request(client.get("/foo"));
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
package io.servicetalk.examples.http.traffic.resilience;

import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.concurrent.api.Single;
import io.servicetalk.http.netty.HttpServers;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpServiceFilter;

/**
* A server that specifies the importance of requests based on the request metadata.
*/
public final class TrafficResilienceServerClassificationExample {

public static void main(String[] args) throws Exception {
Expand All @@ -28,8 +30,9 @@ public static void main(String[] args) throws Exception {
.classifier(() -> (meta) -> "/health".equals(meta.requestTarget()) ? () -> 20 : () -> 100)
.build();

HttpServers.forPort(0)
HttpServers.forPort(8080)
.appendNonOffloadingServiceFilter(resilienceFilter)
.listenAndAwait((ctx, request, responseFactory) -> Single.succeeded(responseFactory.ok()));
.listenBlockingAndAwait((ctx, request, responseFactory) -> responseFactory.ok())
.awaitShutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,22 @@
package io.servicetalk.examples.http.traffic.resilience;

import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.concurrent.api.Single;
import io.servicetalk.http.netty.HttpServers;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpServiceFilter;

/**
* A server that uses the dynamic gradient capacity limiter.
*/
public final class TrafficResilienceServerExample {

public static void main(String[] args) throws Exception {
final TrafficResilienceHttpServiceFilter resilienceFilter =
new TrafficResilienceHttpServiceFilter.Builder(() -> CapacityLimiters.dynamicGradient().build())
.build();

HttpServers.forPort(0)
HttpServers.forPort(8080)
.appendNonOffloadingServiceFilter(resilienceFilter)
.listenAndAwait((ctx, request, responseFactory) -> Single.succeeded(responseFactory.ok()));
.listenBlockingAndAwait((ctx, request, responseFactory) -> responseFactory.ok())
.awaitShutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@

import io.servicetalk.capacity.limiter.api.CapacityLimiter;
import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.concurrent.api.Single;
import io.servicetalk.http.netty.HttpServers;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpServiceFilter;

import static io.servicetalk.http.api.HttpRequestMethod.POST;

/**
* A server that uses two separate capacity limiters, selected based on request metadata.
*/
public final class TrafficResilienceServerPartitionExample {

public static void main(String[] args) throws Exception {
Expand All @@ -33,8 +35,9 @@ public static void main(String[] args) throws Exception {
return meta -> meta.method() == POST ? setLimiter : getLimiter;
}, true).build();

HttpServers.forPort(0)
HttpServers.forPort(8080)
.appendNonOffloadingServiceFilter(resilienceFilter)
.listenAndAwait((ctx, request, responseFactory) -> Single.succeeded(responseFactory.ok()));
.listenBlockingAndAwait((ctx, request, responseFactory) -> responseFactory.ok())
.awaitShutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@

import io.servicetalk.capacity.limiter.api.CapacityLimiter;
import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.concurrent.api.Single;
import io.servicetalk.http.netty.HttpServers;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpServiceFilter;

import static io.servicetalk.capacity.limiter.api.CapacityLimiters.composite;
import static io.servicetalk.buffer.api.CharSequences.contentEqualsIgnoreCase;
import static java.util.Arrays.asList;

/**
* A server that uses fixed capacity limiters based on the customer identity, as determined by the request metadata.
*/
public final class TrafficResilienceServerQuotasExample {
static final CharSequence CUSTOMER = "x-customer";
static final CharSequence CUSTOMER_X = "X";
Expand All @@ -39,8 +41,9 @@ public static void main(String[] args) throws Exception {
}, true)
.build();

HttpServers.forPort(0)
HttpServers.forPort(8080)
.appendNonOffloadingServiceFilter(resilienceFilter)
.listenAndAwait((ctx, request, responseFactory) -> Single.succeeded(responseFactory.ok()));
.listenBlockingAndAwait((ctx, request, responseFactory) -> responseFactory.ok())
.awaitShutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
package io.servicetalk.examples.http.traffic.resilience;

import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.concurrent.api.Single;
import io.servicetalk.http.netty.HttpServers;
import io.servicetalk.traffic.resilience.http.ServiceRejectionPolicy;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpServiceFilter;

/**
* A server that stops accepting new connections when it reaches its rejection threshold.
*/
public final class TrafficResilienceServerStopAcceptingExample {

public static void main(String[] args) throws Exception {
Expand All @@ -33,8 +35,9 @@ public static void main(String[] args) throws Exception {
.rejectionPolicy(rejectionPolicy)
.build();

HttpServers.forPort(0)
HttpServers.forPort(8080)
.appendNonOffloadingServiceFilter(resilienceFilter)
.listenAndAwait((ctx, request, responseFactory) -> Single.succeeded(responseFactory.ok()));
.listenBlockingAndAwait((ctx, request, responseFactory) -> responseFactory.ok())
.awaitShutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
package io.servicetalk.examples.http.traffic.resilience;

import io.servicetalk.capacity.limiter.api.CapacityLimiters;
import io.servicetalk.concurrent.api.Single;
import io.servicetalk.http.netty.HttpServers;
import io.servicetalk.traffic.resilience.http.TrafficResilienceHttpServiceFilter;

import java.util.concurrent.RejectedExecutionException;

/**
* An example that demonstrates custom handling of tickets on error conditions.
*/
public final class TrafficResilienceServerTerminalsExample {

public static void main(String[] args) throws Exception {
Expand All @@ -36,8 +38,9 @@ public static void main(String[] args) throws Exception {
})
.build();

HttpServers.forPort(0)
HttpServers.forPort(8080)
.appendNonOffloadingServiceFilter(resilienceFilter)
.listenAndAwait((ctx, request, responseFactory) -> Single.succeeded(responseFactory.ok()));
.listenBlockingAndAwait((ctx, request, responseFactory) -> responseFactory.ok())
.awaitShutdown();
}
}
Loading

0 comments on commit 799574e

Please sign in to comment.