armeria-0.53.0
Breaking changes
-
#696 Replace
PathMappingswithRouterand change the API ofPathMapping- Improve the service router by using Trie-based data structure
- It is possible to implement more complicated service routing such as content negotiation.
-
#717 #727 #729 #733 #737 #747 Use Micrometer as the primary metric collection library.
-
Replace
(Dropwizard|Prometheus)MetricCollecting(Client|Service)with
MetricCollecting(Client|Service)ServerBuilder sb = new ServerBuilder(); sb.service(...., myService.decorate( MetricCollectingService.newDecorator(MeterIdFunction.ofDefault())));
-
Replace
DropwizardMetricsCircuitBreakerListenerwith
MetricCollectingCircuitBreakerListener -
Replace
PathMapping.metricName()withPathMapping.meterTag() -
Add
Server.meterRegistry()andClientFactory.meterRegistry()-
The default registry is
Metrics.globalRegistry. -
A user can override the default registry using
ServerBuilder.meterRegistry(..),ClientFactoryBuilder.meterRegistry(..)andClientFactory.setMeterRegistry(..).ServerBuilder sb = new ServerBuilder(); sb.meterRegistry(NoopMeterRegistry.get()); // Disable metrics
-
-
Add
RequestContext.meterRegistry() -
Add various utilities for Micrometer to
common.metric
-
-
#720
RetryStrategy.shouldRetry()now returnsCompletableFuture<Optional<BackOff>>to allow a user to choose a differentBackofffor a different failure cause.// Use fixed delay on 500 and exponential delay on 503. Backoff backoffOn500 = Backoff.fixed(3000); Backoff backoffOn503 = Backoff.exponential(1000, 60000); RetryStrategy<HttpRequest, HttpResponse> strategy = RetryStrategy.onStatus(httpStatus -> { if (httpStatus == HttpStatus.SERVICE_UNAVAILABLE) { return Optional.of(backoffOn503); } else if (httpStatus == HttpStatus.INTERNAL_SERVER_ERROR) { return Optional.of(backoffOn500); } else { return Optional.empty(); } });
-
#749 Rename
PrometheusExporterHttpServicetoPrometheusExpositionService
New features
-
#690 #710 Easier
Serverintegration test withServerRule-
A new module
armeria-testingcontains a JUnit ruleServerRule, which enables easier integration testing of aServer.public class MyTest { @ClassRule // or @Rule if you want to start a new Server for each test method. public static final ServerRule server = new ServerRule() { @Override protected void configure(ServerBuilder sb) throws Exception { sb.service("/myService", ...); } }); @Test public void myTest() throws Exception { // ServerRule provides various utility methods for getting URIs and port numbers. HttpClient client = HttpClient.of(server.uri("/")); AggregatedHttpMessage response = client.get("/myService").aggregate().get(); assertThat(response.content().toStringUtf8()).isEqualTo("Hello, world!"); } }
-
-
#694
DnsAddressEndpointGroupandDnsServiceEndpointGroupwhich uses DNS A/AAAA and SRV records respectively. -
#696 Media type negotiation for annotated services using
@ConsumerTypeand@ProducerTypeServerBuilder sb = new ServerBuilder(); sb.annotatedService(new Object() { @Get("/greet") @ProduceType("application/json;charset=UTF-8") public HttpResponse greetGet(@Param("name") String name) { return HttpResponse.of(HttpStatus.OK, MediaType.JSON_UTF_8, "{\"name\":\"%s\"}", name); } @Post("/greet") @ConsumeType("application/x-www-form-urlencoded") public HttpResponse greetPost(@Param("name") String name) { return HttpResponse.of(HttpStatus.OK); } });
-
#701 Add
StreamMessageDuplicator.duplicateStream(boolean)for potentially reduced memory footprint and more convenience.HttpRequestDuplicator dup = new HttpRequestDuplicator(req); HttpRequest firstDuplicate = dup.duplicateStream(); HttpRequest lastDuplicate = dup.duplicateStream(true); // No need to call dup.close(); underlying buffered content will be // removed automatically as the duplicate streams are consumed.
-
#711 Provide a simpler way to add gRPC services.
-
GrpcServicenow implements a new interfaceServiceWithPathMappingswhich allows a user not to specify path mapping:ServerBuilder sb = new ServerBuilder(); sb.service(new GrpcServiceBuilder() .addService(new MyGrpcServiceOne()) .supportedSerializationFormats(GrpcSerializationFormats.values()) .build()) .service(new GrpcServiceBuilder() .addService(new MyGrpcServiceTwo()) .addService(new MyGrpcServiceThree()) .supportedSerializationFormats(GrpcSerializationFormats.values()) .build(), authDecorator);
-
-
This doesn't work only for
GrpcServicebut anyServiceWithPathMappingsimplementations. -
#728 Add session-level options for client-side initial HTTP/2 settings
ClientFactory cf = new ClientFactoryBuilder() .initialHttp2ConnectionWindowSize(1048576) .initialHttp2StreamWindowSize(131072) .http2MaxFrameSize(32768) .build();
-
#735 Allow specifying alternative timeout for retry attempts. e.g. Set the timeout of each attempt to 1 second while
RetryingClientwill give up 10 seconds after the initial attempt.// Retry when could not receive a resonse before timeout. RetryStrategy<HttpRequest, HttpResponse> strategy = new RetryStrategy<HttpRequest, HttpResponse>() { final Backoff backoff = Backoff.fixed(1000); @Override public CompletableFuture<Optional<Backoff>> shouldRetry(HttpRequest request, HttpResponse response) { return response.aggregate().handle((result, cause) -> { if (cause instanceof ResponseTimeoutException) { return Optional.of(backoff); } return Optional.empty(); }); } }; HttpClient client = new HttpClientBuilder("http://example.com/") .decorator(RetryingHttpClient.newDecorator( strategy, /* defaultMatAttempts */ 10, /* responseTimeoutForEachAttempt */ 1000)) .build();
Improvements
- #696 Service router now uses Caffeine as its caching layer, and its stats are exported to Micrometer.
- #721 Implement
Server.toString() - #750 Log stacktrace for error responses in
LoggingService
Bug fixes
- #579 #696 Inability to bind two annotated methods at the same path with different HTTP methods. e.g. one at
/greetfor GET and the other at/greetfor POST - #714 #715 A request whose path contains an asterisk (*) is not handled correctly.
- #722 #748
HttpResponseproduced byTomcatServicedoes not containcontent-lengthheader. - #731 Add missing
service(ServiceWithPathMappings,...)toAbstractVirtualHostBuilder - #744 A race condition in
DeferredStreamMessagecauses a subscription leak. - #748
JettyServicefails withIllegalStateExceptionwhenResourceHandlertries to serve the resource greated than 8192 bytes.
Dependencies
- Brave 4.5.1 -> 4.6.0
- Caffeine 2.5.3 -> 2.5.5
- Dropwizard Metrics 3.2.3 -> 3.2.4
- gRPC 1.4.0 -> 1.6.1
- Guava 22.0 -> 23.0
- Kafka 0.10.2.1 -> 0.11.0.0
- Netty 4.1.13 -> 4.1.15
- Reactive Streams 1.0.1-RC1 -> 1.0.1
- Spring Boot 1.5.4 -> 1.5.6
- Tomcat 8.5.16 -> 8.5.20 / 8.0.45 -> 8.0.46