All Versions
14
Latest Version
Avg Release Cycle
15 days
Latest Release
1 day ago

Changelog History
Page 1

  • v0.98.2

    February 18, 2020

    ๐Ÿฑ ๐Ÿ’ฎ What is Armeria?

    Armeria is an open-source asynchronous HTTP/2 RPC/REST client/server library built on top of Java 8, Netty, Thrift and gRPC. Its primary goal is to help engineers build high-performance asynchronous microservices that use HTTP/2 as a session layer protocol. Visit the official web site and follow @armeria_project to check out many cool features you can't find in the official gRPC/Thrift implementation or other microservice frameworks.

    ๐Ÿฑ ๐ŸŒŸ New features

    • ๐Ÿ— You can now specify any client options when building with ArmeriaRetrofitBuilder, because it extends AbstractClientOptionsBuilder. #2483

      Retrofit retrofit = ArmeriaRetrofit.builder("http://example.com") .factory(...) .decorator(...) .responseTimeout(...) .build();

    ๐Ÿ“ˆ Improvements

    • โœ… FallthroughException is not a part of the internal API anymore, so you can refer to it when testing your annotation service extensions. #2495

    ๐Ÿ› ๏ธ Bug fixes

    • Armeria clients will not violate the MAX_CONCURRENT_STREAMS setting enforced by an HTTP/2 server anymore. #2256 #2374
    • ๐Ÿ›  Fixed a regression where Server fails to read PKCS#5 a private key since 0.98.0 #2485
    • RequestContextExporter does not export an entry whose value is null anymore. #2492
    • ๐Ÿ“„ DocService does not fail with a ReflectionsException on startup anymore. #2491 #2494
    • ๐Ÿ›  Fixed some potential buffer leaks. #2497 #2498 #2499 #2500

    ๐Ÿฑ โ›“ Dependencies

    • Brave 5.9.4 โ†’ 5.9.5
    • gRPC 1.27.0 โ†’ 1.27.1
      • Protobuf 3.11.3 โ†’ 3.11.4
    • Micrometer 1.3.3 โ†’ 1.3.5
    • Tomcat 9.0.30 โ†’ 9.0.31, 8.5.50 โ†’ 8.5.51
    • ZooKeeper 3.5.6 โ†’ 3.5.7
    • Shaded dependencies:
      • fastutil 8.3.0 โ†’ 8.3.1

    ๐Ÿฑ ๐Ÿ™‡ Thank you

    ๐Ÿš€ This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:

  • v0.98.1

    February 10, 2020
  • v0.98.0

    February 08, 2020
  • v0.97.0

    December 06, 2019
  • v0.96.0

    November 23, 2019

    ๐Ÿฑ ๐Ÿ’ฎ What is Armeria?

    Armeria is an open-source asynchronous HTTP/2 RPC/REST client/server library built on top of Java 8, Netty, Thrift and gRPC. Its primary goal is to help engineers build high-performance asynchronous microservices that use HTTP/2 as a session layer protocol. Visit the official web site and follow @armeria_project to check out many cool features you can't find in the official gRPC/Thrift implementation or other microservice frameworks.

    ๐Ÿฑ ๐ŸŒŸ New features

    • ๐Ÿ‘€ The type signature of clients and services has been greatly simplified. Note that this involves various breaking changes unfortunately. See the 'Breaking changes' section for the details. #2239 #2254

      // Before:public class FooHttpService implements Service<HttpRequest, HttpResponse> { ... }public class FooRpcService implements Service<RpcRequest, RpcResponse> { ... }public class FooHttpClient implements Client<HttpRequest, HttpResponse> { ... }public class FooRpcClient implements Client<RpcRequest, RpcResponse> { ... }Service<HttpRequest, HttpResponse> foo(Service<HttpRequest, HttpResponse> bar) { ... }Function<Service<HttpRequest, HttpResponse>, ? extends Service<HttpRequest, HttpResponse>> httpServiceDecorator;Function<Service<RpcRequest, RpcResponse>, ? extends Service<RpcRequest, RpcResponse>> rpcServiceDecorator;Function<Client<HttpRequest, HttpResponse>, ? extends Client<HttpRequest, HttpResponse>> httpClientDecorator;Function<Client<RpcRequest, RpcResponse>, ? extends Client<RpcRequest, RpcResponse>> rpcClientDecorator;// After:public class FooHttpService implements HttpService { ... }public class FooRpcService implements RpcService { ... }public class FooHttpClient implements HttpClient { ... }public class FooRpcClient implements RpcClient { ... }HttpService foo(HttpService bar) { ... }Function<? super HttpService, ? extends HttpService> httpServiceDecorator;Function<? super RpcService, ? extends RpcService> rpcServiceDecorator;Function<? super HttpClient, ? extends HttpClient> httpClientDecorator;Function<? super RpcClient, ? extends RpcClient> rpcClientDecorator;

    • You can now specify service-level settings for annotated services, just like other service types. #2180 #2222

      Server server =Server.builder() .annotatedService().pathPrefix("/api") .requestTimeoutMillis(5000) .exceptionHandler((ctx, req, cause) -> ...) .build(new Object() { ... })) .build();

    • 0๏ธโƒฃ RequestContext now has its own RequestId, which is a 64-bit random integer by default. #2001 #2174 #2203 #2224

      Server server =Server.builder() .service("/", (ctx, req) -> { return HttpResponse.of("Request ID: %s", ctx.id().text()); }) .build();

    • You can now add a cause to an HttpStatusException. #2253

      HttpService service = (ctx, req) -> { try (FileInputStream in = new FileInputStream(...)) { ... } catch (FileNotFoundException e) { throw HttpStatusException.of(HttpStatus.NOT_FOUND, e); } };

    • Armeria server now always has a fallback service which is matched when no routes match a request. #1625 #2255

      • As a result, a route decorator bound at prefix:/ can intercept any requests, even the requests not handled by any services:

      // CorsService will intercept any requests,// even the ones not handled by any services.Server server =Server.builder() .service("/foo", fooService) .service("/bar", barService) .routeDecorator().pathPrefix("/") .build(CorsService.newDecorator(...)) .build();

    • ๐ŸŒฒ You can now determine the log level of LoggingClient and LoggingService dynamically. #2250 #2258

      LoggingClient.builder() .requestLogLevel(log -> ...) .responseLogLevel(log -> { if (log.responseCause() == null || log.responseCause() instanceof HarmlessException) { return LogLevel.INFO; } else { return LogLevel.WARN; } });

    • ClientFactoryOptions has been added to allow programmatic access to the ClientFactory settings. #2230

      ClientFactory factory = ...;boolean pipelining = factory.options().useHttp1Pipelining();

    • 0๏ธโƒฃ You can now disable Armeria's Netty-based asynchronous DNS resolver by specifying -Dcom.linecorp.armeria.useJdkDnsResolver=true JVM option. Use it only when the default resolver does not work. #2261

    ๐Ÿฑ ๐Ÿ’ช Improvements

    • Armeria client does not block a request anymore when DNS resolution takes long time. #2017 #2217 #2231
    • You do not have to prepend none+ prefix to non-RPC URIs anymore. #2219 #2241

      // Before:Clients.of("none+https://...", ...);// After:Clients.of("https://...", ...);

      • The behavior of Scheme.parse() and tryParse() has been improved in the same manner:

      // Scheme.parse() now uses SerializationFormat.NONE automatically:assert Scheme.parse("http") == Scheme.parse("none+http");

    ๐Ÿ› ๏ธ Bug fixes

    • ๐Ÿ”ง Armeria Spring auto-configuration now works correctly even when only GrpcServiceRegistrationBeans are given. #2234
    • RequestContext is not pushed more often than necessary anymore when notifying RequestLogListeners. #2227
    • DynamicEndpointGroup now handles the case where an endpoint address does not change but only a weight. #2240
    • ๐Ÿ‘€ HttpStatusException now respects Flags.verboseExceptionSampler(). #2253
    • AccessLogWriter does not fail with a ClassCastException anymore. #2259
    • ๐Ÿ›  Fixed a bug where a service receives an OPTIONS request even if the service did not opt-in for OPTIONS method. #2263

    ๐Ÿฑ ๐Ÿš๏ธ Deprecations

    • ๐Ÿ—„ ClientFactory.DEFAULT has been deprecated in favor of ClientFactory.ofDefault().
    • ๐Ÿ—„ The getters for host-level settings in ServerConfig have been deprecated. #2244 #2246

      // Before:HttpService service = (ctx, req) -> { return HttpResponse.of("maxRequestLength: %d", ctx.server().maxRequestLength()); };// After:HttpService service = (ctx, req) -> { return HttpResponse.of("maxRequestLength: %d", ctx.virtualHost().maxRequestLength()); };

    • ๐Ÿ— Continuing the migration to static builder() factory methods, the following classes have switched from constructors to static builder() methods: #2221

      • ClientCacheControl
      • ClientConnectionTimings
      • ClientDecoration
      • ClientFactory
      • ClientOptions
      • ClientRequestContext
      • EndpointInfo
      • FieldInfo
      • HttpClient
      • LoggingClient
      • LoggingService
      • RequestContextCurrentTraceContext
      • RetrofitMeterIdPrefixFunction
      • ServerCacheControl
      • ServiceRequestContext

    ๐Ÿฑ โ˜ข๏ธ Breaking changes

    • The signatures of RequestContext.newDerivedContext() have been changed so they always require RequestId, HttpRequest and RpcRequest for less ambiguity. #2209 #2224
    • ๐Ÿ“œ Scheme.parse() and tryParse() do not fail anymore even if the scheme does not start with none+: #2219 #2241

      // Scheme.parse() now uses SerializationFormat.NONE automatically:assert Scheme.parse("http") == Scheme.parse("none+http");

    • ClientBuilderParams.uri() does not return a URI with none+ prefix anymore. #2219 #2241

    • HttpClient interface has been renamed to WebClient. HttpClient is now a different interface that extends Client<HttpRequest, HttpResponse>. #2254

      // Doesn't work:HttpClient client = HttpClient.of("https://www.google.com/");// Good:WebClient client = WebClient.of("https://www.google.com/");

    • Services must implement HttpService or RpcService and clients must implement HttpClient or RpcClient: #2239 #2254

      // Before:public class FooHttpService implements Service<HttpRequest, HttpResponse> { ... }public class FooRpcService implements Service<RpcRequest, RpcResponse> { ... }public class FooHttpClient implements Client<HttpRequest, HttpResponse> { ... }public class FooRpcClient implements Client<RpcRequest, RpcResponse> { ... }// After:public class FooHttpService implements HttpService { ... }public class FooRpcService implements RpcService { ... }public class FooHttpClient implements HttpClient { ... }public class FooRpcClient implements RpcClient { ... }

      • You'll have to change any Service<...> and Client<...> usages in your code into HttpService, RpcService, HttpClient or RpcClient, unless you intended to express both HTTP- and RPC- level types.

      // Before:Service<HttpRequest, HttpResponse> foo(Service<HttpRequest, HttpResponse> bar) { ... }// After:HttpService foo(HttpService bar) { ... }

      • Similarly, you must use SimpleDecoratingHttpClient or SimpleDecoratingRpcClient instead of SimpleDecoratingClient, and SimpleDecoratingHttpService or SimpleDecoratingRpcService instead of SimpleDecoratingService.

      // Does not work:class MyDecoratorService extends SimpleDecoratingService<HttpRequest, HttpResponse> { MyDecoratorService(Service<HttpRequest, HttpResponse> delegate) { super(delegate); } ...}// Good:class MyDecoratorService extends SimpleDecoratingHttpService { // Note the constructor parameter change.MyDecoratorService(HttpService delegate) { super(delegate); } ...}

      • If you implemented your decorator without extending the SimpleDecorating{Http,Rpc}Service or SimpleDecorating{Http,Rpc}Client, then you must make sure that it implements HttpService, RpcRequest, HttpClient or RpcClient.

      // Does not work:class MyDecoratorService implements Service<HttpRequest, HttpResponse> { final Service<HttpRequest, HttpResponse> delegate; MyDecoratorService(Service<HttpRequest, HttpResponse> delegate) { this.delegate = delegate; } ...}// Good:class MyDecoratorService implements HttpService { // Note the type change.final HttpService delegate; // Note the constructor parameter change.MyDecoratorService(HttpService delegate) { this.delegate = delegate; } ...}

    • Service.decorate() has been pushed down to HttpService and RpcService: #2239 #2254

      // Does not work:Service<HttpRequest, HttpResponse> service = (ctx, req) -> ...; service.decorate(myDecorator); // No such method// Good:HttpService service (ctx, req) -> ...; service.decorate(myDecorator); // OK!

    • The type parameters of decorator Functions have been changed. #2239 #2254

      // Before:Function<Service<HttpRequest, HttpResponse>, ? extends Service<HttpRequest, HttpResponse>> httpServiceDecorator;Function<Service<RpcRequest, RpcResponse>, ? extends Service<RpcRequest, RpcResponse>> rpcServiceDecorator;Function<Client<HttpRequest, HttpResponse>, ? extends Client<HttpRequest, HttpResponse>> httpClientDecorator;Function<Client<RpcRequest, RpcResponse>, ? extends Client<RpcRequest, RpcResponse>> rpcClientDecorator;// After:Function<? super HttpService, ? extends HttpService> httpServiceDecorator;Function<? super RpcService, ? extends RpcService> rpcServiceDecorator;Function<? super HttpClient, ? extends HttpClient> httpClientDecorator;Function<? super RpcClient, ? extends RpcClient> rpcClientDecorator;

    • Some types, which could be used at both HTTP- and RPC- level, have been split into two different types. For example:

      • DecoratingClientFunction has been split into DecoratingHttpClientFunction and DecoratingRpcClientFunction.
      • DecoratingServiceFunction has been split into DecoratingHttpServiceFunction and DecoratingRpcServiceFunction.
      • LoggingClient has been split into LoggingClient and LoggingRpcClient.
      • ServiceWithRoutes has been split into HttpServiceWithRoutes and RpcServiceWithRoutes.
      • TransientService has been split into TransientHttpService and TransientRpcService.
    • The following services are now provided only at HTTP-level. Please let us know if you need an RPC-level version of them.

      • LoggingService
      • MetricCollectingService
      • StructuredLoggingService
      • KafkaStructuredLoggingService

    ๐Ÿฑ โ›“ Dependencies

    • Brave 5.8.0 -> 5.9.0
    • gRPC 1.24.1 -> 1.25.0
    • Jackson 2.10.0 -> 2.10.1
    • Micrometer 1.3.0 -> 1.3.1
    • Netty TCNative BoringSSL 2.0.26 -> 2.0.27
    • Protobuf 3.9.1 -> 3.10.0
    • RxJava 2.2.13 -> 2.2.14
    • SLF4J 1.7.28 -> 1.7.29
    • Spring Boot 2.1.9 -> 2.1.10

    ๐Ÿฑ ๐Ÿ™‡ Thank you

    ๐Ÿš€ This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:

  • v0.95.0

    October 26, 2019

    ๐Ÿฑ ๐ŸŒŸ What is Armeria?

    Armeria is an open-source asynchronous HTTP/2 RPC/REST client/server library built on top of Java 8, Netty, Thrift and gRPC. Its primary goal is to help engineers build high-performance asynchronous microservices that use HTTP/2 as a session layer protocol. Visit the official web site and follow @armeria_project to check out many cool features you can't find in the official gRPC/Thrift implementation or other microservice frameworks.

    ๐Ÿฅณ New features

    • You can now bind multiple paths to an annotated service easily using @Path. #1822 #1870

      @Get@Post@Path("/a")@Path("/b")public String myAwesomeServcie(...) {...}

    • You can now make an annotated service run from blockingTaskExecutor by attaching @Blocking. #2078, #2187

      @Get("/myHeavyTask")@Blockingpublic HttpResponse reallyHeavyComputation(...) {...}

    • 0๏ธโƒฃ Armeria server now adds Server and Date headers to responses by default. #2137, #2188

      • If you do not want that behavior, you should call:

      Server.builder() .service(...) .disableServerHeader() .disableDateHeader() .build();

    • ๐Ÿ”ง You can now configure a Caffeine cache spec for HttpFileService. #916, #2142

      HttpFileServiceBuilder.forClassPath("/") .entryCacheSpec("maximumSize=512") .build()

    Or, using JVM option:
    -Dcom.linecorp.armeria.fileServiceCache=maximumSize=1024,expireAfterAccess=600s

    • ๐Ÿ‘€ You can now see the Armeria version in the metric. #2179

    ๐Ÿฑ ๐Ÿ’ช Improvements

    • Armeria server startup time is reduced to 80 percent when TLS is not used. #1645, #2184
    • ๐ŸŽ The performance of getting HTTP timestamps is improved by caching the values every second. #2196
      • Use HttpTimestampSupplier.currentTime() to take advantage of it.
    • ๐ŸŽ The performance of finding service is improved by not making an unused Map in RouteResult. #2153
    • ๐ŸŽ The performance of gRPC call is improved by using the singleton HTTP headers when a service does not create a new HTTP headers. #2152
    • ๐ŸŽ The performance of making metric Tags is improved by adding Tags in ascending order. #2150, #2163
    • ๐Ÿ“„ We now have favicon in our DocService. #2186

    ๐Ÿฑ ๐Ÿ‘ป Bug fixes

    • ServerHttpRequest.getRemoteAddress() now returns proper address. #2208
    • ๐Ÿ‘€ You can now see descriptive error messages when sslContext is not configured properly. #1844, #2124
    • ๐Ÿ— You can now build (Request|Response)Headers multiple times using builders. #2190, #2193
      • Previously, it raised ClassCastException if build() is called twice.
    • ๐Ÿ”ง NoRequestContextException is not raised anymore if you configure the name of the non-request thread.

      RequestContextCurrentTraceContext.builder() .nonRequestThread("RMI TCP Connection") .build()

    • NullPointerException is not raised anymore in Http1ClientCodec when the server sends multiple responses for one request. #2210

    • ๐Ÿ‘€ You can now see the access logs when the method of a request is not allowed and there are no services that match the path. #2159

    ๐Ÿšซ Breaking changes

    • 0๏ธโƒฃ All annotated services are run from EventLoop by default. #2187
      • Previously, if the return type is neither HttpResponse nor CompletableFuture, annotated services are run from blockingTaskExecutor.
    • ServerBuilder.tls() now throws a checked SSLException. #2124
    • ๐Ÿšš ServerBuilder.sslContext() methods are completly removed. #2124

    ๐Ÿฑ โ›“ Dependencies

    • Brave 5.7.0 -> 5.8.0
    • โฌ‡๏ธ Dropwizard 4.1.0 -> 4.1.1
    • gRPC 1.24.0 -> 1.24.1
    • Netty 4.1.42 -> 4.1.43
    • org.bouncycastle 1.63 -> 1.64
    • Prometheus 0.7.0 -> 0.8.0
    • RxJava2 2.2.12 -> 2.2.13
    • Spring Boot 2.1.8 -> 2.1.9
    • Tomcat
      • 9.0.26 -> 9.0.27
      • 8.5.43 -> 8.5.47
    • ZooKeeper 3.5.5 -> 3.5.6

    ๐Ÿฑ ๐Ÿ™‡โ€โ™‚๏ธ Thank you

    ๐Ÿš€ This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:

  • v0.94.0

    October 04, 2019

    What is Armeria?

    Armeria is an open-source asynchronous HTTP/2 RPC/REST client/server library built on top of Java 8, Netty, Thrift and gRPC. Its primary goal is to help engineers build high-performance asynchronous microservices that use HTTP/2 as a session layer protocol. Visit the official web site and follow @armeria_project to check out many cool features you can't find in the official gRPC/Thrift implementation or other microservice frameworks.

    ๐Ÿ†• New features

    • ๐Ÿ“š You can now decorate multiple services by path mapping. See the documentation for more information. #582 #2040 #2057

      ServerBuilder sb = new ServerBuilder();// Register vipService and memberService under '/users' pathsb.annotatedService("/users/vip", vipService) .annotatedService("/users/members", memberService); // Decorate all services under '/users' pathsb.decoratorUnder("/users", (delegate, ctx, req) -> { if (!authenticate(req)) { return HttpResponse.of(HttpStatus.UNAUTHORIZED); } return delegate.serve(ctx, req); });

    ๐Ÿ— You can also use fluent route builder with routeDecorator() to decorate more than one service by path mapping.

    // Decorate services under '/users' path with fluent route buildersb.routeDecorator() .pathPrefix("/users") .build((delegate, ctx, req) -\> { if (!authenticate(req)) { return HttpResponse.of(HttpStatus.UNAUTHORIZED); } return delegate.serve(ctx, req); });
    
    • You can now get the current HttpRequest and RpcRequest from RequestContext so you donโ€™t need to downcast Request to HttpRequest or RpcRequest. #2089 #2120

      // Before: Request req = ctx.request();if (req instanceof HttpRequest) { RequestHeaders headers = (HttpRequest) req).headers(); }// After:RequestHeaders headers = ctx.request().headers();// Before:if (req instanceof RpcRequest) { String rpcMethod = (RpcRequest) requestContent).method(); }// After:// rpcRequest() method will return null when the request being handled is not// an RPC request or not decoded into an RPC request yet.String rpcMethod = ctx.rpcRequest().method();

    • You can now set example headers when using {Annotated,Grpc,Thrift}ServiceRegisrationBean for Spring Boot integration. #2100

      @Beanpublic AnnotatedServiceRegistrationBean annotatedService() { return new AnnotatedServiceRegistrationBean() .setServiceName("annotatedService") .setService(new AnnotatedService()) // Add exmample headers for annotated service .addExampleHeaders("x-additional-header", "headerVal") .addExampleHeaders("get", "x-additional-header", "headerVal"); }

    • ๐Ÿ— You can now create the following classes using the builder() method instead of their *Builder constructors. #1719 #2085

      • CircuitBreaker
      • CircuitBreakerHttpClient
      • CircuitBreakerRpcClient
      • DnsAddressEndpointGroup
      • DnsServiceEndpointGroup
      • DnsTextEndpointGroup
      • GrpcService
      • Server
      • RetryingHttpClient
      • RetryingRpcClient

      // Before:Server server = new ServerBuilder() .service("/hello", (ctx, req) -> HttpResponse.of(OK)) .build();// After:Server server = Server.builder() .service("/hello", (ctx, req) -> HttpResponse.of(OK)) .build();

    ๐Ÿ‘Œ Improvement

    ๐Ÿ› Bug fixes

    • ResponseTimeoutException is not logged more than once anymore when the response has been timed out. #2000 #2138
    • ๐Ÿ‘€ You no longer see AbortedStreamException while sending long-lived requests with RetryingHttpClient. #2134
    • ๐Ÿ‘€ You can now see a warning message when JSON request conversion fails in an annotated service. #2041 #2131

    ๐Ÿ—„ Deprecations

    • ๐Ÿ—„ AbstractBindingBuilder.pathUnder(String prefix) has been deprecated in favor of pathPrefix(String prefix). #2040
    • ๐Ÿ—„ RouteBuilder.prefix(String prefix, ...) has been deprecated in favor of pathPrefix(String prefix, ...). #2040
    • ๐Ÿ—„ RouteBuilder.pathWithPrefix(String prefix, String pathPattern) has been deprecated in favor of path(String prefix, String pathPattern). #2040
    • ๐Ÿ— new *Builder() constructors which are mentioned in 'New Features' have been deprecated in favor of *.builder(). #1719 #2085

    ๐Ÿ’ฅ Breaking changes

    • ๐Ÿšš armeria-zipkin has been removed for further clean-up. #2120
    • RequestContext.request() returns HttpRequest instead of Request. #2120
      • RequestContext.updateRequest() always updates an HttpRequest. It returns void now because it never fails, unless null is specified.
      • RequestContext.newDerivedContext(Request) now requires both HttpRequest and RpcRequest.
    • 0๏ธโƒฃ A default virtual host service can serve any virtual host requests. #2057 #2040
      • Before: If a custom virtual host fails to match the given request to a service, it returns NOT_FOUND status.
      • After: If a custom virtual host fails to match the given request to a service, looking up a default virtual host services to match the request.
    • AbstractStreamMessageDuplicator.close() does not abort all children StreamMessages. #2134
      • You should use AbstractStreamMessageDuplicator.abort() to abort all children StreamMessages anymore.

    Dependencies

    • gRPC 1.23.0 -> 1.24.0
    • โฌ‡๏ธ Dropwizard Metrics 4.0.0 -> 4.1.0
    • Jetty 9.4.20.v20190813 -> 9.4.21.v20190926
    • Jackson 2.9.9.20190807 -> 2.10.0
    • Java JWT 3.8.2 -> 3.8.3
    • Micrometer 1.2.1 -> 1.3.0

    Thank you

    ๐Ÿš€ This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:

  • v0.93.0

    September 25, 2019

    What is Armeria?

    Armeria is an open-source asynchronous HTTP/2 RPC/REST client/server library built on top of Java 8, Netty, Thrift and gRPC. Its primary goal is to help engineers build high-performance asynchronous microservices that use HTTP/2 as a session layer protocol. Visit the official web site and follow @armeria_project to check out many cool features you can't find in the official gRPC/Thrift implementation or other microservice frameworks.

    ๐Ÿ†• New features

    • You can now create a Sampler from a specification string such as random=0.1 and rate-limited=10. #2108

      • This is going to be useful when you want to make the sampling policy of Brave{Client,Server} or Logging{Client,Server} configurable from external sources such as a configuration file or a system property.

      Sampler<Object> randomSampler = Sampler.of("random=0.1");Sampler<Object> rateLimitedSampler = Sampler.of("rate-limited=10");Sampler<Object> alwaysSampler = Sampler.of("always");Sampler<Object> neverSampler = Sampler.of("never");

    • ๐Ÿ‘€ You can now specify the Sampler specification string in the com.linecorp.armeria.verboseExceptions system property. #2105 #2111

      • From this release, the default value of this property is rate-limited=10 which means the stack trace of the exceptions will be recorded at the maximum rate of 10 exceptions/sec. Previously, the default value of this property was false, which eliminates all stack traces, which gave our users a hard time figuring out why.
    • You can now specify a common path prefix using @PathPrefix annotation in annotated services. #2031 #2099

      @PathPrefix("/users")public class MyUserService { @Get("/{id}") // Mapped to '/users/{id}'@ProducesJsonpublic User getUser(@Param int id) { ... } ...}Server server = new ServerBuilder() .annotatedService(new MyUserService()) .build();

    ๐Ÿ› Bug fixes

    • ๐Ÿ›  Fixed a memory leak in HealthCheckService. #2110
    • Prometheus and Dropwizard Metrics are now optional dependencies in armeria-spring-boot-*. #2106 #2107
    • armeria-spring-boot-actuator-autoconfigure does not refuse to start anymore when HealthStatusHttpMapper is missing. #2104

    ๐Ÿ’ฅ Breaking changes

    • ๐Ÿ‘€ Flags.verboseExceptions() has been replaced with verboseExceptionSampler() and verboseExceptionSamplerSpec(). #2111
    • ๐Ÿšš Exceptions.isVerbose(), which was deprecated previously, has been removed. #2111
    • โฌ†๏ธ You may need to add io.micrometer:micrometer-registry-prometheus or io.dropwizard.metrics:metrics-json after upgrading if you were depending on them transitively. #2107

    Dependencies

    • Netty 4.1.41 -> 4.1.42
    • Netty TCNative BoringSSL 2.0.25 -> 2.0.26
    • Project Reactor 3.2.12 -> 3.3.0
    • Prometheus 0.6.0 -> 0.7.0
    • Retrofit 2.6.1 -> 2.6.2

    Thank you

    ๐Ÿš€ This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:

  • v0.92.0

    September 23, 2019

    What is Armeria?

    Armeria is an open-source asynchronous HTTP/2 RPC/REST client/server library built on top of Java 8, Netty, Thrift and gRPC. Its primary goal is to help engineers build high-performance asynchronous microservices that use HTTP/2 as a session layer protocol. Visit the official web site and follow @armeria_project to check out many cool features you can't find in the official gRPC/Thrift implementation or other microservice frameworks.

    ๐Ÿ†• New features

    • You can now easily get the request URI using RequestHeaders.uri() and HttpRequest.uri(). #2092

      RequestHeaders headers = RequestHeaders.of(HttpMethod.GET, "/foo", HttpHeaderNames.SCHEME, "https", HttpHeaderNames.AUTHORITY, "example.com"));assert headers.uri().equals(URI.create("https://example.com/foo"));assert HttpRequest.of(header).uri() == headers.uri();

    • You can now decorate the Runnable of the Thread created using ThreadFactoryBuilder. #2047 #2067

      ThreadFactories.builder(...) .eventLoop(true) .daemon(true) .priority(...) .taskFunction(task -> { // Specify your logic here so it's executed before the Runnable. task.run(); // Specify your logic here so it's executed after the Runnable. }) .build();

    • ๐Ÿ”ง You can now configure Server using Consumer<ServerBuilder> as well as ArmeriaServerConfigurator when integrating with Spring Boot. #2070

      @Beanpublic Consumer<ServerBuilder> customizer() { return sb -> sb.port(...) ... .service(...); }

    • You can now set example requests using AnnotatedServiceRegistrationBean. #1855 #2026

      @Beanpublic AnnotatedServiceRegistrationBean okService() { return new AnnotatedServiceRegistrationBean() .setServiceName("myAnnotatedService") .setPathPrefix("/my_service") .setService(new MyAnnotatedService()) .setExampleRequests(Lists.of( AnnotatedExampleRequest.of("myMethod", "{\"foo\":\"bar\"}"))); }

    • You can be aware of whether the response content is empty from an HTTP status code. #2058

      HttpStatus status = ...if (!status.isContentAlwaysEmpty()) { // We may have a body!}

    • You can use SettableHealthIndicator for health check responses when using Spring boot autoconfigure. #2088

    ๐Ÿ‘Œ Improvements

    • ๐Ÿ‘€ You will see the doc service automatically scrolls down to the debug form if the URL contains a request. #1682 #2045
    • ๐ŸŽ The performance for parsing a struct context in Thrift is improved, thanks to the Stack-Walking API in Java 9. #1686 #2055
    • ๐Ÿ‘€ You will see the int values of Enum members if they have in doc service. #1966 #2015
    • ๐Ÿ“œ RequestContext instead of RequestLog is used for trace parsing and sampling. #2038

    ๐Ÿ› Bug fixes

    • ๐ŸŒ You can now get the gRPC web trailers in the client. #2030 #2076
    • The actuator now responds with the correct Spring boot content type. #2061
    • The blocking stub in gRPC now can read messages. #2065 #2066
    • The listeners for EndpointGroup are notified after the first health check even when all endpoints are unhealthy. #2074 #2075
    • The subscriber who subscribes to the Response from a WebClient gets notified when it's complete. #2080 #2087
    • ๐ŸŒฒ IllegalStateException that indicates the log should have at least one child is no longer raised when retrying. #2082 #2083
    • โฑ DefaultEventLoopScheduler respects maxNumEventLoopsPerHttpHttp1Endpoint set from ClientFactoryBuilder. #2086

    ๐Ÿ—„ Deprecation

    • ๐Ÿ—„ The EventLoopThreadFactory has been deprecated in favor of ThreadFactories. #2067

      ThreadFactory factory = ThreadFactories.builder("myThread") .eventLoop(true) .build();

    ๐Ÿ’ฅ Breaking changes

    • Specifying an :authority header in a request has no effect anymore. The current Endpoint always determines the authority. #2092

      // This does NOT work anymore.final HttpClient client = HttpClient.of("https://127.0.0.1:8080/"); client.execute(RequestHeaders.of(HttpMethod.GET, "/", HttpHeaderNames.AUTHORITY, "foo.com"));// This works.final HttpClient client =HttpClient.of(SessionProtocol.HTTPS, Endpoint.of("foo.com", 8080).withIpAddr("127.0.0.1")); client.get("/");

      • Instead, you can now use ClientOption.HTTP_HEADERS or {Client,Service}RequestContext.additional{Request,Response}{Headers,Trailers}() to override the existing headers, including :authority. #2092

      // This works.final HttpHeaders customHeaders =HttpHeaders.of(HttpHeaderNames.AUTHORITY, "foo.com");final HttpClient client =HttpClient.of("http://127.0.0.1:8080/", ClientOption.HTTP_HEADERS.newValue(customHeaders)); client.get("/");// This also works.final HttpClient client = HttpClient.of("http://127.0.0.1:8080/");try (SafeCloseable ignored = Clients.withHttpHeader( HttpHeaderNames.AUTHORITY, "foo.com")) { client.get("/"); }

    • ExceptionHandlerFunction.handleExeption() accepts ServiceRequestContext instead of RequestContext. #2060

      • You don't have to downcast anymore. :)
    • ๐Ÿšš GrpcServiceRegistrationBean.ExampleRequest has been removed. Use GrpcExampleRequest.

    Dependencies

    • Micrometer 1.2.0 -> 1.2.1
    • Netty 4.1.39.Final -> 4.1.41.Final
    • Tomcat 9.0.24 -> 9.0.26
      • Tomcat8 8.5.43 -> 8.5.45

    Thank you

    ๐Ÿš€ This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:

  • v0.91.0

    September 06, 2019

    What is Armeria?

    Armeria is an open-source asynchronous HTTP/2 RPC/REST client/server library built on top of Java 8, Netty, Thrift and gRPC. Its primary goal is to help engineers build high-performance asynchronous microservices that use HTTP/2 as a session layer protocol. Visit the official web site and follow @armeria_project to check out many cool features you can't find in the official gRPC/Thrift implementation or other microservice frameworks.

    ๐Ÿ†• New features

    • You can specify the maximum number of event loops to handle connections. #1886

      ClientFactoryBuilder builder = ...; builder.maxNumEventLoopsPerEndpoint(5); // Assign 5 event loops for endpoints. 1 is used by default.builder.maxNumEventLoopsPerHttp1Endpoint(10); // Assign 10 event loops for HTTP/1.1 endpoints. 1 is used by default.// You can set a customized function.builder.maxNumEventLoopsFunction(endpoint -> { if (endpoint.equals(Endpoint.of("foo.com"))) { return 5; } if (endpoint.host().contains("bar.com")) { return Integer.MAX_VALUE; // The value will be clamped at the number of event loops. } return -1; // Should return 0 or a negative value to use the default value.});

    • โฑ You can now implement your own EventLoopScheduler which schedules EventLoops those handle connections. #1886

    • ๐Ÿ‘€ You can now see Armeria modules and their versions in DocService. #685 #1744
      version

    • You can now easily combine EndpointGroups and Endpoints. #1897 #1939

      Endpoint foo = ...;Endpoint bar = ...;DynamicEndpointGroup group1 = ...;DynamicEndpointGroup group2 = ...;EndpointGroup composite = EndpointGroup.of(foo, bar, group1, group2);

    • You can use the Fibonacci backoff. #1968 #1979

      Backoff backoff = Backoff.fibonacci(100 /* initial delay millis */, 10000 /* max delay millis */);

    • ๐Ÿ”ง You can now reuse the configuration of exising Armeria client when creating an Armeria Retrotit client and HealthCheckedEndpointGroup. #2019 #2020

      HttpClient myClient = ...;ArmeriaRetrofitBuilder builder = new ArmeriaRetrofitBuilder();// Use the same settings and decorators with myClient when sending requests.builder.clientOptions(myClient.options());HealthCheckedEndpointGroupBuilder builder2 = new HealthCheckedEndpointGroupBuilder(); builder2.clientOptions(myClient.options());

    • You can unwrap a Client and bring the decorating client instance via Unwrappable.as() or ClientFactory.unwrap(). #1883 #2018 #2029

      HttpClient client = new HttpClientBuilder() .decorator(LoggingClient.newDecorator()) .build();LoggingClient unwrapped = client.as(LoggingClient.class).get();LoggingClient unwrapped2 = clientFactory.unwrap(client, LoggingClient.class).get();

    • You can now easily retrieve the port number of the running server. #1956 #1967

      ServerBuilder sb = new ServerBuilder();Server server = sb.http(0) // Use an ephemeral port. .build();...int port = server.activeLocalPort();

    ๐Ÿ‘Œ Improvements

    • ๐ŸŽ The delay calculation performance in ExponentialBackoff is improved. #1983
    • You can now run all Armeria examples using gradle run or gradle bootRun. #1988

    ๐Ÿ› Bug fixes

    • ๐Ÿ‘€ You no longer see a warning message when the connection is closed before the current session protocol is detected. #2043 #2048
    • ๐Ÿ‘ป ByteBufHttpData does not leak anymore when an exception is raised by a client-side decorator. #2034
    • โฌ‡๏ธ You no longer see a NullPointerException when the remote server requires a protocol downgrade. #2010 #2021

    ๐Ÿ’ฅ Breaking changes

    • 0๏ธโƒฃ Only one HTTP/2 connection is made per endpoint by default. #1886
      • Previously, an Armeria client made as many connections as the number of event loops for each endpoint. Now, it creates only one connection per endpoint so one EventLoop handles all requests. Because of that, you may see performance degradation. If you want it to work as before, specify maxNumEventLoopsPerEndpoint with the number of event loops in ClientFactoryBuilder.

    Dependencies

    We now use Maven Boms(Bill of Materials) for Jackson, Brave and Netty

    • Brave 5.6.10 -> 5.7.0
    • Guava 28.0-jre -> 28.1-jre
    • Jackson 2.9.9 -> 2.9.9.20190807
    • net.shibboleth.utilities 7.3.0 -> 7.5.0
    • OpenSAML 3.3.0 -> 3.4.3
    • Reactivestreams 1.0.2 -> 1.0.3
    • ๐Ÿš€ Reactor 3.2.11.RELEASE -> 3.2.12.RELEASE
    • RxJava2 2.2.11 -> 2.2.12
    • ๐Ÿš€ Spring boot 2.1.7.RELEASE -> 2.1.8.RELEASE

    Thank you

    ๐Ÿš€ This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests: