0.84.0 release notes

23rd April 2019

New features

  • You can now access the detailed timing information for the connection attempts made by Armeria via RequestLog API, including DNS lookup and socket connect time. #1692

    HttpClient client = new HttpClientBuilder("https://example.com/")
        .decorator((delegate, ctx, req) -> {
            ctx.log().addListener(log -> {
                ClientConnectionTimings timings = ClientConnectionTimings.get(log);
                System.err.printf("Total time taken: %d ns%n",
                                  timings.connectionAcquisitionDurationNanos());
                System.err.printf("DNS lookup: %d ns%n",
                                  timings.dnsResolutionDurationNanos());
                System.err.printf("Socket connect:: %d ns%n",
                                  timings.socketConnectDurationNanos());
            }, RequestLogAvailability.REQUEST_START);
            return delegate.execute(ctx, req);
        })
        .build();
    client.get("/");
  • You can now customize server-side SslContext more conveniently. #1717

    ServerBuilder sb = new ServerBuilder();
    sb.tls(certChainFile, keyFile, tlsContextBuilder -> {
        // Use JDK SSLEngine instead of OpenSSL.
        tlsContextBuilder.sslProvider(SslProvider.JDK);
    });
  • Server.stop() is now able to stop its blockingTaskExecutor. You have to specify whether to stop the blockingTaskExecutor you specified or not when calling ServerBuilder.blockingTaskExecutor() from this release. #1685 #1707

    ServerBuilder sb = new ServerBuilder();
    // The thread pool will be terminated when the server stops.
    sb.blockingTaskExecutor(Executors.newFixedThreadPool(100), true);
  • The usability of RedirectService has been improved with some API changes. #1725 #1726

    • RedirectService preserves the query string by default. The query string of the old location was dropped previously.
    • Added preserveQueryString constructor parameter. Specifying false will let you go back to the previous behavior.
  • The usability of SettableHealthChecker has been improved with some API changes. #1714

    • SettableHealthChecker's initial healthiness is now true. It was false previously.
    • You can now specify the initial healthiness when instantiating SettableHealthChecker.
      SettableHealthChecker myHealthChecker = new SettableHealthChecker(false);
      ServerBuilder sb = new ServerBuilder();
      sb.service("/monitor/health", new HttpHealthCheckService(myHealthChecker));
    • SettableHealthChecker.setHealthy(boolean) is now chainable. #1714
      // Same with: new SettableHealthChecker(false)
      SettableHealthChecker myHealthChecker = new SettableHealthChecker().setHealthy(false);
  • You can now specify different path mappings for different CORS policies. #1698 #1699

    • Using a builder pattern:

      ServerBuilder sb = new ServerBuilder();
      // Add two services under /foo and /bar.
      sb.service("prefix:/foo", fooService);
      sb.service("prefix:/bar", barService);
      
      // Enable CORS for:
      // - GET and POST requests for all resources under http://example.com/foo/
      // - GET request for all resources under http://example.com/bar/
      sb.decorator(CorsServiceBuilder.forOrigins("http://example.com")
                                     .pathMapping("prefix:/foo")
                                     .allowCredentials()
                                     .allowRequestMethods(HttpMethod.GET, HttpMethod.POST)
                                     .andForOrigins("http://example.com")
                                     .pathMapping("prefix:/bar")
                                     .allowCredentials()
                                     .allowRequestMethods(HttpMethod.GET)
                                     .and()
                                     .newDecorator());
    • Using annotations:

      sb.annotatedService(
          @CorsDecorator(
              origins = "http://example.com",
              pathPatterns = "prefix:/foo",
              credentialsAllowed = true,
              allowedRequestMethods = { HttpMethod.GET, HttpMethod.POST })
          @CorsDecorator(
              origins = "http://example.com",
              pathPatterns = "prefix:/bar",
              credentialsAllowed = true,
              allowedRequestMethods = { HttpMethod.GET })
          new Object() {
              ...
          });
  • You can now build a gRPC service without depending on upstream gRPC API. #1720 #1727

    • Added armeria-grpc-protocol which provides a core functionality required for building a gRPC service, which does not depend on io.grpc:grpc-java but only on com.google.protobuf:protobuf-java.

    • Added AbstractUnaryGrpcService which allows you to implement a unary gRPC easily without depending on io.grpc:grpc-java.

      class MyUnaryGrpcService extends AbstractUnaryGrpcService {
          @Override
          protected CompletableFuture<byte[]> handleMessage(byte[] message) {
              final MyGrpcRequest req;
              try {
                  req = MyGrpcRequest.parseFrom(message);
              } catch (InvalidProtocolBufferException e) {
                  throw new UncheckedIOException(e);
              }
      
              MyGrpcResponse res = MyGrpcResponse.newBuilder()...build();
              return UnmodifiableFuture.completedFuture(res.toByteArray());
          }
      }
  • Spring Boot integration now has content encoding options. #1716

    # Your application.yml:
    armeria:
      ports:
        - port: 8080
          protocols: HTTP
      compression:
        enabled: true
        mime-types: text/*, application/json
        excluded-user-agents: some-user-agent, another-user-agent
        minResponseSize: 1KB

Bug fixes

  • The default path pattern now handles a trailing slash properly. #1730 #1735
  • TwoElementFixedStreamMessage no longer throws an IllegalReferenceCountException. #1687 #1695
  • DnsEndpointGroup does not ignore the search directive in /etc/resolv.conf anymore. This fix should be useful for users in Kubernetes environment. #1694 #1697
  • DocService no longer raises a NullPointerException for a certain gRPC service metadata. #1705 #1715
  • An unframed gRPC service no longer becomes unresponsive when sending a response without content #1723
  • THttpService no longer fails to load the service metadata when .thrift file was compiled with the private-members option. #1728 #1729
  • THttpService no longer fails to load the service metadata when .thrift file defines a service that extends other service. #1734
  • HttpTracingClient and HttpTracingService do not fill service name automatically with host names or IP addresses anymore. #1706
  • Spring integration module now respects the com.linecorp.armeria.useOpenSsl flag properly. #1713

Deprecations

  • ServerBuilder.blockingTaskExecutor(Executor) has been deprecated. Use ServerBuilder.blockingTaskExecutor(Executor, boolean). #1685 #1707
  • TextFormatter.epoch() and appendEpoch() have been deprecated. Use TextFormatter.epochMillis() and appendEpochMillis(). #1692

Breaking changes

  • The initial healthiness of SettableHealthChecker is now true. #1714
  • RedirectService preserves the query string by default. The query string of the old location was dropped previously. #1725 #1726

Dependencies

  • gRPC 1.19.0 -> 1.20.0
    • Protobuf 3.6.1 -> 3.7.1
  • Jetty 9.4.15 -> 9.4.17
  • Micrometer 1.1.3 -> 1.1.4
  • Spring Boot 2.1.3 -> 2.1.4, 1.5.19 -> 1.5.20
  • Tomcat 9.0.17 -> 9.0.19, 8.5.39 -> 8.5.40
  • ZooKeeper 3.4.13 -> 3.4.14

Thank you