armeria

Your go-to microservice framework for any situation, from the creator of Netty et al. You can build any type of microservice leveraging your favorite technologies, including gRPC, Thrift, Kotlin, Retrofit, Reactive Streams, Spring Boot and Dropwizard.

APACHE-2.0 License

Stars
4.7K
Committers
243

Bot releases are visible (Hide)

armeria -

Published by trustin about 4 years ago

See the release notes for the complete change list.

armeria -

Published by minwoox over 4 years ago

See the release notes for the complete change list.

armeria -

Published by trustin over 4 years ago

See the release notes for the complete change list.

armeria -

Published by ikhoon over 4 years ago

See the release notes for the complete change list.

armeria -

Published by trustin over 4 years ago

See the release notes for the complete change list.

armeria -

Published by trustin over 4 years ago

💮 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.

📈 Improvements

  • ConcurrencyLimitingClient now disables the limit when maxConcurrency is Integer.MAX_VALUE. #2667

🛠️ Bug fixes

  • Fixed a memory leak where a HEAD request is not cleaned up properly in a certain case. #2666
  • DNS query timeouts are now handled correctly when querying for A and AAAA records at the same time. #2664 #2665
  • Fixed a noisy IllegalStateException while handling a failed connection attempt. #2671

🙇 Thank you

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

  • @anuraaga
  • @bw-moon
  • @ikhoon
  • @jacobis
  • @kojilin
  • @minwoox
  • @trustin
armeria -

Published by trustin over 4 years ago

💮 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

  • Added RetryStrategy.onException() #2652
  • Armeria clients can now send an OPTIONS * HTTP/1 request as an alternative to an HTTP/2 PING frame. #2636
    • This feature is disabled by default and you can enable it by:
      • specifying com.linecorp.armeria.defaultPingIntervalMillis system property
      • or calling ClientFactoryBuilder.pingIntervalMillis().

📈 Improvements

  • DocService debug form now prettifies any JSON responses. #2635

🛠️ Bug fixes

  • grpc-timeout gRPC client header is generated correctly now. #2643
  • QueryParams.toQueryString() does not raise an exception anymore. #2644
  • HealthCheckedEndpointGroup does not raise aConcurrentModificationException anymore. #2647
  • Thrift TEXT protocol does not fail to handle a recursive union struct anymore. #2654
  • MoreNamingConventions.prometheus() now appends the seconds suffix for LongTaskTimer correctly, when using legacy meter names. #2646
  • Fixed a bug where DocService sends a request with a wrong HTTP method if a service specification contains duplicate methods. #2657

☢️ Breaking changes

  • com.linecorp.armeria.defaultHttp2PingTimeoutMillis flag has been replaced with com.linecorp.armeria.defaultPintIntervalMillis.
  • com.linecorp.armeria.defaultUseHttp2PingWhenNoActiveStreams flag has been removed without a replacement, because:
    • HTTP/2 can send PING frame regardless of whether there is an active stream or not.
    • HTTP/1 can only send OPTIONS * HTTP/1.1 when there is no active stream.
  • ClientFactoryBuilder.http2PingTimeoutMillis() has been replaced with ClientFactoryBuilder.pingIntervalMillis().
  • ServerBuilder.http2PingTimeoutMillis() has been replaced with ServerBuilder.pingIntervalMillis().

⛓ Dependencies

  • Brave 5.10.2 → 5.11.2

🙇 Thank you

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

  • @adriancole
  • @AmosDoan
  • @anuraaga
  • @eugene70
  • @gary-lo
  • @hueneburg
  • @huydx
  • @ikhoon
  • @mauhiz
  • @minwoox
  • @trustin
armeria -

Published by minwoox over 4 years ago

💮 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.

⛓ Dependencies

  • Dropwizard 2.0.2 -> 2.0.5
  • Retrofit 2.8.0 -> 2.8.1
  • Spring Boot 2.2.5.RELEASE -> 2.2.6.RELEASE
  • Zookeeper 3.6.0 -> 3.5.7

🙇 Thank you

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

  • @anuraaga
  • @ikhoon
  • @minwoox
  • @nurinamu
  • @trustin
armeria -

Published by minwoox over 4 years ago

💮 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.

🛠️ Bug fixes

  • The response is not encoded anymore at EncodingSerivce when the HTTP status indicates the content is empty. #2631

⛓ Dependencies

  • Micrometer 1.4.0 -> 1.3.6

🙇 Thank you

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

  • @anuraaga
  • @ikhoon
  • @mauhiz
  • @minwoox
  • @trustin
armeria -

Published by minwoox over 4 years ago

💮 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 make your client connect via a SOCKS 4, SOCKS 5 or HTTP CONNECT proxy server. #2321 #2496
    ClientFactory.builder()
                 .proxyConfig(ProxyConfig.socks4(socksProxyServer.address()))
                 .build();
    
  • You can now configure to send PING on idle HTTP/2 connections. #1263 #2409
    ClientFactory.builder()
                 .http2PingTimeoutMillis(3000)
                 .build();
    
  • You can now make an alias for the pre-defined MDC key when using RequestContextExportingAppender. #2512 #2531
    <export>request_id=req.id</export>     <!-- request_id is the alias for the built-in property. -->
    <export>my_foo_bar=attr:com.example.Foo#ATTR_BAR</export>    <!-- my_foo_bar is the alias. -->
    
  • You can now set an example path and queries for DocService. #2195 #2546
  • You can now customize the default log name of a service. #2626
    sb.route().addRoute(...).defaultLogName("name").build(service);
    
  • You can now access a parent log from a child log using RequestLogAccess.parent(). #2599
  • gRPC client now supports gRPC CallCredentials. #2619 #2622
  • You can now send customized responses from ThrottlingService using ThrottlingAcceptHandler and ThrottlingRejectHandler. #2482 #2503
  • You can now use advanced throttling algorithm based on Token-Bucket rate-limiting and Bucket4j library. #2566
  • You can now create your own storage to store RequestContext. #2514 #2610
    // You should implement `RequestContextStorageProvider` and use SPI to return the `RequestContextStorage`.
    public class CustomizedStorageProvider implements RequestContextStorageProvider {
        @Override
        public RequestContextStorage newStorage() {
            return new CustomizedStorage();
        }
    }
    

📈 Improvements

  • You can now set timeout using TimeoutMode. #2535 #2571
    // Before
    ctx.extendResponseTimeoutMillis(10000);
    ctx.setResponseTimeoutAfterMillis(10000);
    
    // After
    ctx.setResponseTimeoutMillis(TimeoutMode.EXTEND, 10000);
    ctx.setResponseTimeoutMillis(TimeoutMode.SET_FROM_NOW, 10000);
    
    • set(Request|Response)Timeout is now undeprecated.

🛠️ Bug fixes

  • DNS resolution is timed out after queryTimeoutMillis. #2623
  • You can now return Single<HttpResponse> or Maybe<HttpResponse> in an annotated service. #2624
  • You can now register and monitor Reactor Scheduler with Prometheus in Armeria Server. #2612
  • RequestLog.name and some other properties are copied to the child log in RetyringClient. #2551 #2560
  • You no longer see ClosedStreamException due to the stream creation reversal. #2597
  • IllegalStateException is not raised anymore while building a WebFlux response. #2613
  • Annotated service's log name is always set. #2626

🏚️ Deprecations

  • Deprecated ZooKeeperUpdatingListener.nodeValueCodec() in favor of ZooKeeperUpdatingListener.codec(). #2552

☢️ Breaking changes

  • Most of the deprecated APIs are gone. #2543

    • If you have trouble finding APIs to replace, please upgrade to 0.98.7 first and use your IDE's advanced feature to search deprecated APIs. Then, you can easily upgrade to 0.99.0.
  • armeria-dropwizard is now for Dropwizard 2. If you want to use Dropwizard 1.3.x, use armeria-dropwizard1. #2556

  • armeria-rxjava is now for RxJava 3. If you want to use RxJava 2, use armeria-rxjava2. #2378 #2501

  • ClientBuilder.path(path) is now gone. #2525 #2538

    • If you want to specify the path other than /, you should specify it when creating ClientBuilder.
      // before
      Clients.builer(SessionProtocol.HTTP, Endpoint.of("127.0.0.1"))
             .path("/foo");
      // after
      Clients.builer(SessionProtocol.HTTP, Endpoint.of("127.0.0.1"), "/foo");
      
  • ClosedSessionException now extends ClosedStreamException. #2596 #2616

  • AuthSuccessHandler<HttpRequest, HttpResponse> and AuthFailureHandler<HttpRequest, HttpResponse> now don't have type parameters.

  • The meter name armeriaBlockingTaskExecutor is now blockingTaskExecutor with the prefix armeria.executor.

  • RequestContext.set*TimeoutAfter*() or extend*Timeout*() methods have been removed. Call set*Timeout*() with a TimeoutMode specified instead.

⛓ Dependencies

  • Brave 5.9.5 -> 5.10.2
  • bucket4j-core 4.10.0
  • Curator 4.2.0 -> 4.3.0
  • java-jwt 3.10.0 -> 3.10.1
  • jetty-alpn-agent 2.0.9 -> 2.10.0
  • Micrometer 1.3.5 -> 1.4.0
  • Netty 4.1.37.Final -> 4.1.48.Final
    • netty-tcnative-boringssl-static 2.0.29.Final -> 2.0.30.Final
  • Opensaml 3.4.3 -> 3.4.5
  • Reactor 3.3.3.RELEASE -> 3.3.4.RELEASE
  • Retrofit 2.7.2 -> 2.8.0
  • RxJava 3.0.0 -> 3.0.1
  • Spring Boot 2.2.4 -> 2.2.5
    • Spring2.1 2.1.12.RELEASE -> 2.1.13.RELEASE
  • Tomcat 9.0.31 -> 9.0.33
    • Tomcat8.5 8.5.51 -> 8.5.53
  • Zookeeper 3.5.7 -> 3.6.0

🙇 Thank you

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

  • @adriancole
  • @alex-lx
  • @AmosDoan
  • @andrewom
  • @anuraaga
  • @cricket007
  • @heowc
  • @hexoul
  • @ikhoon
  • @imasahiro
  • @jyblue
  • @joschi
  • @jrhee17
  • @KarboniteKream
  • @kojilin
  • @mauhiz
  • @max904-github
  • @minwoox
  • @rstoyanchev
  • @sivaalli
  • @trustin
armeria -

Published by trustin over 4 years ago

💮 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.

🛠️ Bug fixes

  • Fixed a bug where an exception is not wrapped by UnprocessedRequestException in a certain case. #2594

🙇 Thank you

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

  • @ikhoon
  • @minwoox
  • @trustin
armeria -

Published by trustin over 4 years ago

💮 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

  • Added TextFormatter.socketAddress() and inetAddress() that convert a SocketAddress or an InetAddress into a String without repeating an IP address twice. #2591

📈 Improvements

  • RequestContext.toString() now returns a String that includes its RequestId. #2591

🛠️ Bug fixes

  • Fixed a bug where a client-side response is not closed quickly enough for a certain case. #2590
  • Fixed a bug where Sampler.random(0.01) never samples. #2592
  • The Logger returned by RequestContext.makeContextAware(Logger) now pushes the context whenever logging a message, so that RequestContextExporter can retrieve the current context. #2587

🙇 Thank you

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

  • @anuraaga
  • @ikhoon
  • @KarboniteKream
  • @minwoox
  • @trustin
armeria -

Published by trustin over 4 years ago

💮 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 use UUID as a parameter in your annotated service. #2573 #2577
    public class MyAnnotatedService {
        @Get("/user/by-uuid/{uuid}")
        public User findUserByUuid(@Param UUID uuid) { ... }
    }
    
  • LogLevel.OFF and LogLevel.log(Logger, String, Object...) have been added. #2532

📈 Improvements

  • ClosedSessionException and ClosedStreamException now have a specific cause or message to help you understand why a connection or a stream has been closed. #2580
  • A once-per-thread warning message will now be logged, as well as throwing an exception, when a user pushes a context incorrectly. #2583
  • Some common socket exceptions raised by annotated services are not logged anymore by default to reduce the amount of less useful log messages. #2572

🛠️ Bug fixes

  • ConcurrencyLimitingClient does not fail with an 'illegal context' error under load anymore. #2579
  • RetryingClient and RetryingRpcClient handles negative System.nanoTime() values correctly now. #2584
  • Fixed a bug where RetryingClient and RetryingRpcClient do not complete a request when RetryStrategy or RetryStrategyWithContent throws an exception. #2581
  • EventLoopCheckingFuture and its subtypes do not warn about blocking operation anymore when they are done already. #2564

⛓ Dependencies

  • Dropwizard Metrics 4.1.4 → 4.1.5
  • gRPC 1.27.2 → 1.28.0
  • Netty 4.1.46 → 4.1.47
  • RxJava 2.2.18 → 2.2.19

🙇 Thank you

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

  • @adriancole
  • @anuraaga
  • @ikhoon
  • @kojilin
  • @minwoox
  • @renaudb
  • @tobias-
  • @trustin
armeria -

Published by trustin over 4 years ago

💮 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.

🛠️ Bug fixes

  • HealthCheckService does not leak the event loop tasks it scheduled anymore. #2557
  • ServiceRequestContext.setRequestTimeout() and ClientRequestContext.setResponseTimeout() now schedules a timeout correctly even if no timeout was scheduled before. #2537
  • Made sure Subscriber.onError() is invoked rather than onComplete() when a StreamMessage has been aborted. #2539
  • Fixed specification violations in our Reactive Streams Subscriber implementations. #2533

⛓ Dependencies

  • Dropwizard 1.3.19 → 1.3.20
  • Dropwizard Metrics 4.1.3 → 4.1.4
  • gRPC 1.27.1 → 1.27.2
  • Jackson 2.10.2.20200130 → 2.10.3
  • Netty 4.1.45 → 4.1.46
    • netty-tcnative-boringssl-static 2.0.28 → 2.0.29
  • Jetty 9.4.26 → 9.4.27
  • Project Reactor 3.3.2 → 3.3.3
  • Retrofit 2.7.1 → 2.7.2

🙇 Thank you

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

  • @anuraaga
  • @cricket007
  • @ikhoon
  • @joschi
  • @minwoox
  • @trustin
armeria -

Published by trustin over 4 years ago

💮 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

  • RequestContextExporter and RequestContextExportingAppender for Logback can now export the current request ID into MDC. #2511
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
      <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
          <pattern>%d{HH:mm:ss.SSS} %X{req.id} %msg%n</pattern>
        </encoder>
      </appender>
      <appender name="RCEA" class="com.linecorp.armeria.common.logback.RequestContextExportingAppender">
        <appender-ref ref="CONSOLE" />
        <export>req.id</export>
      </appender>
    </configuration>
    
  • Client-side options API (ClientOption and ClientFactoryOption) has been revamped. #2523
    • ClientOptions.get() and ClientFactoryOptions.get() never throw an exception. A default value is returned for an unspecified option. Therefore, other getter methods such as getOrElse() have been removed.

📈 Improvements

  • You'll now get a ClosedStreamException instead of Http2Exception when your HTTP/2 connection was closed due to an RST_STREAM frame. #2508

🛠️ Bug fixes

  • *ClientBuilder.options(ClientOptions) now overrides only the specified options. #2516
    ClientFactory factory = ClientFactory.insecure();
    ClientOptions options = ClientOptions.builder()
                                         .responseTimeMillis(5000)
                                         .build();
    WebClient client = WebClient.builder("http://foo.com")
                                .factory(factory)
                                .options(options)
                                .build();
    // This assertion does not fail anymore.
    assert client.options().factory() == ClientFactory.insecure();
    
  • Fixed a bug where DocService throws the java.lang.IllegalStateException: zip file closed exception while starting up. #2518 #2519
  • MetricCollectingClient does not count the request that failed initially due to a connection refused error and then succeeded after a retry as failure anymore. #2517
  • Fixed a bug where LoggingClient and LoggingSerivce does not push the current context when logging. #2528
  • RequestContextExporter and RequestContextExportingAppender can now export a single custom attribute into multiple MDC properties. #2521
  • RequestContextExporter and RequestContextExportingAppender does not export outdated custom attributes anymore. #2520
  • Renamed incorrect meter ID armeria.server.pendingResponses into armeria.server.pending.responses. #2506
  • The Date header is now encoded properly even when System.nanoTime() returns a negative value. #2530
  • GrpcStatus.fromThrowable() now treats ContentTooLargeException as RESOURCE_EXHAUSTED rather than INTERNAL_ERROR. #2523

☢️ Breaking changes

  • ClientOptions.getOrElse() and getOrNull() have been removed. get() always returns a non-null value now. #2523
  • ClientOptions.asMap() and ClientFactoryOptions.asMap() now return only the options overridden by a user. You can get the Set of available options using ClientOptions.allOptions() or ClientFactoryOptions.allOptions(): #2516 #2523
    ClientOptions myOptions = ...;
    Map<ClientOption<?>, Object> map = new IdentityHashMap<>();
    for (ClientOption o : ClientOptions.allOptions()) {
        map.put(myOptions.get(o));
    }
    
  • ClientOptions.valueOf() and ClientFactoryOptions.valueOf() have been split into two methods: define() and of() #2523.
    • Use of() if you're getting an existing option.
    • Use define() if you're defining a new option.
  • You might need to adjust your monitoring system if you were watching armeria.server.pendingResponses, which has been renamed to armeria.server.pending.responses in this release. #2506

⛓ Dependencies

  • Dropwizard 1.3.18 → 1.3.19
  • Dropwizard Metrics 4.1.2 → 4.1.3
  • java-jwt 3.9.0 → 3.10.0
  • RxJava 2.2.17 → 2.2.18
  • Shaded dependencies
    • Reflections 0.9.12 → 0.9.11 (Downgrade)

🙇 Thank you

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

  • @andrewoma
  • @andrey-tpt
  • @anuraaga
  • @Boozilla
  • @ikhoon
  • @jrhee17
  • @JunoJunho
  • @minwoox
  • @trustin
armeria -

Published by trustin over 4 years ago

💮 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:

  • @anuraaga
  • @ikhoon
  • @fukuang
  • @jrhee17
  • @mauhiz
  • @minwoox
  • @themnd
  • @trustin
  • @yuinacor
armeria -

Published by trustin over 4 years ago

💮 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.

🛠️ Bug fixes

  • FileService does not warn about blocking operations anymore. #2473 #2478
  • HealthCheckedEndpointGroup does not fail to check the healthiness of old Armeria servers anymore. #2474

⛓ Dependencies

  • Brave 5.9.3 -> 5.9.4

🙇 Thank you

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

  • @ikhoon
  • @minwoox
  • @trustin
armeria -

Published by trustin over 4 years ago

💮 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.

🎬 Before we begin

This release contains more breaking changes and deprecations than usual, which were necessary for the preparation of 1.0 release and the long term evolution of our API after 1.0. We'd like to apologize for any inconveniences caused by the breaking changes. Please don't forget we're always here for you and do let us know if you have any trouble upgrading, so we can help you!

🌟 New features

  • Since this release, in preparation of 1.0 release, we annotated classes and packages which may have a chance of breaking change with the @UnstableApi annotation. #2445
  • The attribute access API of RequestContext has been revamped for simplicity. #2322
    AttributeKey<String> MY_ATTR = AttributeKey.valueOf("MY_ATTR");
    RequestContext ctx = ...;
    ctx.setAttr(MY_ATTR, "foo");
    assert "foo".equals(ctx.attr(MY_ATTR));
    
  • When a RequestContext is derived or inherited from another RequestContext, the parent context's attributes are now visible from the derived or inherited context: #2322
    AttributeKey<String> MY_ATTR = AttributeKey.valueOf("MY_ATTR");
    ServiceRequestContext parentCtx = ...;
    ClientRequestContext childCtx = ...;
    assert childCtx.root() == parentCtx;
    parentCtx.setAttr(MY_ATTR, "foo");
    // Root context's attributes are visible from its children.
    assert "foo".equals(childCtx.attr(MY_ATTR));
    // Not visible anymore if the attribute is overwritten.
    childCtx.setAttr(MY_ATTR, "bar");
    assert "foo".equals(parentCtx.attr(MY_ATTR));
    assert "bar".equals(childCtx.attr(MY_ATTR));
    
  • {Client,Service}RequestContext now provides more useful ways to schedule request or response timeout: #2343
    Server.builder()
          .service("/svc", myService.decorate((delegate, ctx, req) -> {
              if (req.headers().contains("x-extend-timeout")) {
                  // Extend the timeout by 10 seconds.
                  ctx.extendRequestTimeout(Duration.ofSeconds(10));
              }
              return delegate.serve(ctx, req);
          }));
    
  • RequestLog API has been revamped for safety and usability. #2342
    RequestContext ctx = ...;
    // Asynchronous retrieval:
    ctx.log().whenRequestComplete().thenAccept(log -> {
        // Can't access response properties at compilation level.
        assert log instanceof RequestOnlyLog;
        System.err.println(log.toStringRequestOnly());
    })
    ctx.log().whenComplete().thenAccept(log -> {
        // Can access all properties.
        assert log instanceof RequestLog;
        System.err.println(log.toStringResponseOnly());
    });
    ctx.log().whenAvailable(RequestLogProperty.SESSION).thenAccept(log -> {
        // Advanced use case:
        // Raises an exception if accessing an unavailable property.
        System.err.println(log.channel());
    });
    // Accessing a property ensuring availability:
    ctx.log().ensureRequestComplete().requestEndTimeNanos();
    ctx.log().ensureComplete().responseEndTimeNanos();
    ctx.log().ensureAvailable(RequestLogProperty.RESPONSE_CONTENT)
       .responseContent();
    
  • RequestLog also has a new property NAME, which can be used as a method name in an RPC call, a span name in distributed tracing or any other human-readable string that can be used for identifying a request. #2413
  • Added a new immutable API for encoding and decoding HTTP query strings: #2307
    QueryParams params = QueryParams.builder()
                                    .add("foo", "1")
                                    .add("bar", "2")
                                    .build();
    // Encoding
    String queryString = params.toQueryString();
    assert "foo=1&bar=2".equals(queryString);
    // Decoding
    QueryParams decodedParams = QueryParams.fromQueryString("foo=1&bar=2");
    assert decodedParams.equals(params);
    // Mutation
    QueryParams newParams = params.toBuilder()
                                  .add("baz", "3")
                                  .build();
    assert "foo=1&bar=2&baz=3".equals(newParams.toQueryString());
    
  • Added various convenient boolean getter methods to HttpStatus: #2435
    assert HttpStatus.CONTINUE.isInformational();
    assert HttpStatus.OK.isSuccess();
    assert HttpStatus.FOUND.isRedirect();
    assert HttpStatus.BAD_REQUEST.isClientError();
    assert HttpStatus.SERVICE_UNAVAILABLE.isServerError();
    // No need to write like this anymore
    assert HttpStatus.OK.codeClass() == HttpStatusClass.SUCCESS;
    
  • Added MediaTypeNames which provides String version of well known MediaTypes, which is useful when writing an annotated service: #2438
    class MyAnnotatedService {
        @Get("/download/zip")
        @Produces(MediaTypeNames.ZIP)
        HttpResponse downloadArchive() { ... }
    }
    
  • You can now add {Request,Response}ConverterFunction and ExceptionHandlerFunction to all annotated services in your Server easily. #2316
    Server.builder()
          .annotatedService("/users", userService)
          .annotatedService("/posts", postService)
          .annotatedService("/files", fileService)
          // Applies all extensions to all 3 annotated services.
          .annotatedServiceExtensions(
              commonRequestConverters,
              commonResponseConverters,
              commonExceptionHandlers)
          .build();
    
  • You can now require a route to have HTTP headers and/or query parameters: #2102
    Server.builder()
          // Route to 'myService' only when:
          // - 'x-must-exist' header exists,
          // - and 'bar' query parameter exists.
          .route().get("/foo")
                  .matchesHeaders("x-must-exist")
                  .matchesParams("bar")
                  .build(myService)
    
  • You can now customize the SslContext created from ServerBuilder.tlsSelfSigned() or VirtualHost.tlsSelfSigned(): #2340
    Server.builder()
          .tlsSelfSigned()
          .tlsCustomizer(sslCtxBuilder -> {
              sslCtxBuilder.ciphers(...);
          })
    
  • You can now close an EndpointGroup asynchronously: #2430
    DnsAddressEndpointGroup group =
        DnsAddressEndpointGroup.of("cluster.com", 8080);
    group.whenClosed().thenRun(() -> {
        System.err.println("Closed!");
    });
    group.closeAsync();
    
  • You do not need to register your EndpointGroup to EndpointGroupRegistry for client-side load balancing. Just specify it when you build a client: #2381
    EndpointGroup group = EndpointGroup.of(
        Endpoint.of("node1.cluster.com"),
        Endpoint.of("node2.cluster.com"));
    // Thrift
    HelloService.Iface client =
        Clients.builder("tbinary+http", group)
               .path("/api/thrift/hello")
               .build(HelloService.Iface.class);
    // gRPC
    HelloServiceBlockingStub client =
        Clients.builder("gproto+http", group)
               .build(HelloServiceBlockingStub.class);
    // Web
    WebClient client =
        WebClient.of(SessionProtocol.HTTP, group);
    
  • You can now limit the number of endpoints in HealthCheckedEndpointGroup, which is very useful when there are many candidate endpoints in the group but you want to send requests to only a few of them, to avoid unnecessarily large number of outbound connections: #2177
    HealthCheckedEndpointGroup group =
        HealthCheckedEndpointGroup.builder(delegateGroup, "/health")
                                  .maxEndpointCount(3)
                                  .build();
    
  • You can now capture the ClientRequestContext of your client call with ClientRequestContextCaptor: #2344
    WebClient client = WebClient.of("http://foo.com/");
    try (ClientRequestContextCaptor ctxCaptor = Clients.newContextCaptor()) {
        HttpResponse res = client.get("/");
        ClientRequestContext ctx = ctxCaptor.get();
        ...
    }
    
  • Added ClientFactory.insecure() and ClientFactoryBuilder.tlsNoVerify() to simplify testing SSL/TLS connections with self-signed certificates: #2340
    // Using the default insecure factory
    WebClient.builder("https://127.0.0.1:8443")
             .factory(ClientFactory.insecure())
             .build();
    // Using a custom insecure factory
    WebClient.builder("https://127.0.0.1:8443")
             .factory(ClientFactory.builder()
                                   .tlsNoVerify()
                                   ...
                                   .build())
             .build();
    
  • ClientFactory is now part of ClientOptions for easier creation of derived clients. #2384
    ClientFactory factory = ...;
    WebClient client =
        WebClient.builder(...)
                 .factory(factory)
                 .build();
    WebClient clientCopy =
        WebClient.builder(...)
                 .options(client.options())
                 .build();
    // Note that ClientFactory is copied as well.
    assert client.factory() == clientCopy.factory();
    
  • RetrofitMeterIdPrefixFunction is now capable of adding HTTP method and request path pattern if you specify a Retrofit service class: #2356
  • New module armeria-dropwizard provides the integration with Dropwizard, which allows you to leverage the best of the both worlds. #2236
  • You can now customize DocService when integrating with Spring framework by injecting DocServiceConfigurator: #2327
    @Bean
    public DocServiceConfigurator docServiceConfigurator() {
        // Exclude all Thrift services from DocService.
        return docServiceBuilder -> {
            docServiceBuilder.exclude(DocServiceFilter.ofThrift());
        };
    }
    
  • ServerRule (JUnit 4) and ServerExtension (JUnit 5) now have more getters: #2449
    • Endpoint getters:
      • endpoint(SessionProtocol), httpEndpoint() and httpsEndpoint()
    • URI getters:
      • uri(SessionProtocol), uri(SessionProtocol, SerializationFormat), httpUri(), httpUri(SerializationFormat), httpsUri() and httpsUri(SerializationFormat)
      • The old deprecated getters return String instead of URI.
    • InetSocketAddress getters:
      • socketAddress(SessionProtocol)
  • The CompletableFutures returned by our API will leave a warning log like the following when you perform a blocking operation in an event loop thread: #2275
    Calling a blocking method on CompletableFuture from an event loop or
    non-blocking thread. You should never do this ...
    java.lang.IllegalStateException: Blocking event loop, don't do this.
    
    You can disable this functionality by specifying the -Dcom.linecorp.armeria.reportBlockedEventLoop=false JVM option.
  • You can now serialize and deserialize ThriftCall, ThriftReply, TMessage and TBase into TTEXT JSON using ThriftJacksonModule. #2439
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new ThriftJacksonModule());
    
  • You can now make any SLF4J Logger context-aware with RequestContext.makeContextAware(Logger): #2341
    // Prints 'Hello!'
    Logger logger = ...;
    logger.info("Hello!");
    // Prints '[<current context>] Hello!'
    Logger ctxAwareLogger = ctx.makeContextAware(logger);
    ctxAwareLogger("Hello!");
    
  • RequestContextExporter is now part of the core API, allowing you to integrate with other logging frameworks than Logback, such as Log4J2. #2314
  • You can now disable HTTP header validation the the -Dcom.linecorp.armeria.validateHeaders=false JVM option.

📈 Improvements

  • Slightly reduced memory footprint of Logging{Client,Service} #2341
  • UnknownHostException raised by Armeria now explains what DNS query has failed. #2332
  • WebClient now accepts a URI that starts with none+ as well. #2361
  • HealthCheckedEndpointGroup now logs a helpful warning message when it receives a 4XX response. #2401
  • Our builder API Javadoc does not show mysterious return type parameter such as B and SELF anymore. #2454
  • A client now gets SSLException instead of ClosedSessionException if a connection attempt fails with an SSL/TLS handshake error. #2338

🔒 Security fixes

  • N/A

🛠️ Bug fixes

  • WebClient does not omit a request query string when sending a request to an absolute URI. #2309
  • A user cannot start a Server with a misconfigured SslContext anymore. #2325
  • A user now always gets the correct RequestContext even if the contexts are nested. #1083
  • Fixed a bug where thread-local context customizers were called for derived contexts unintentionally. #2344
  • Clients.withHttpHeaders() and withContextCustomizer() now work with gRPC calls. #2344
  • ClientRequestContext.path() now returns a correct path for gRPC client calls. #2344
  • You can now send a POST request with an empty body with DocService client. #2357
  • Server-side route cache hit ratio was not as good as we intended. #2358
  • Fixed various potential memory leak in HttpResponseWriter. #2359
  • Long-polling health check mechanism now detects a stall server which accepts a connection but does not send any response. #2392
  • ClientFactoryOptions does not raise a NullPointerException anymore. #2387
  • An AsyncMethodCallback specified when making an async Thrift call now has thread-local ClientRequestContext set properly. #2383
  • gRPC client and server now works well with non-official gRPC stub generators such as reactive-grpc. #2376
  • Fixed a bug where a Server can be started back after close() is called. #2406
  • Fixed a regression where Reactor does not treat Armeria's event loop threads as non-blocking. #2404
  • Armeria does not fail to initialize anymore even if it failed to load the com.linecorp.armeria.versions.properties file. #2398
  • You'll not see the cannot start a new stream with a DATA frame errors anymore. #2429
  • RequestLog.requestStartTime property now includes the time taken for making a connection attempt and the time taken by decorators. #2436
  • The -Dcom.linecorp.armeria.dumpOpenSslInfo=true JVM option does not trigger a StackOverflowError anymore. #2418
  • Fixed cosmetic issues in DocService client sidebar. #2470
  • Made sure IPv6 DNS queries are not sent to some IPv4 only machines with a link-local IPv6 interface. #2464

🏚️ Deprecations

  • HttpParameters has been deprecated in favor of QueryParams #2307
  • ServerBuilder.tls() methods that require a Consumer have been deprecated. Use tlsCustomizer(Consumer) instead. #2340
    // Before:
    Server.builder()
          .tls(..., sslCtxBuilder -> { ... });
    // After:
    Server.builder()
          .tls(...)
          .tlsCustomizer(sslCtxBuilder -> { ... });
    
  • Many classes which have Http in their names have been deprecated in favor of those without Http, e.g. #2323
    • RetryingHttpClient -> RetryingClient
    • HttpFileService -> FileService
  • Many builder classes' constructors have been deprecated in favor of builder() static methods, e.g. #1719
    • new ClientBuilder() -> Clients.builder()
    • new ArmeriaRetrofitBuilder() -> ArmeriaRetrofit.builder()
    • new ServerCacheControlBuilder() -> ServerCacheControl.builder()
  • Many public static final fields that are not truly constants have been deprecated in favor of static factory methods, e.g.
    • EndpointSelectionStrategy.ROUND_ROBIN -> roundRogin()
    • NodeValueCodec.DEFAULT -> ofDefault()
    • AuthTokenExtractors.BASIC -> basic()
  • MoreNamingConventions has been deprecated because we follow Micrometer's recommended naming convention. #2367
  • Version.identify() has been deprecated in favor of getAll() #2398
  • ServiceRequestContext.setRequestTimeout*() has been deprecated in favor of extendRequestTimeout*(), setRequestTimeoutAfter*(), setRequestTimeoutAt*() and clearRequestTimeout(). #2343
  • ClientRequestContext.setResponseTimeout*() has been deprecated in favor of extendResponseTimeout*(), setResponseTimeoutAfter*(), setResponseTimeoutAt*() and clearResponseTimeout(). #2343
  • Many methods that return a CompletableFuture have been renamed from *Future() to when*(), e.g. #2427
    • HttpRequest.completionFuture() -> whenComplete()
    • HttpResponseWriter.onDemand() -> whenConsumed()
    • EndpointGroup.initialEndpointsFuture() -> whenReady()
  • Many URI-returning methods in ServerRule and ServerExtension have been deprecated in favor of the new methods that do not require a path parameter: #2449
    ServerExtension server = ...;
    // Before
    server.httpUri("/");
    server.httpUri("/foo");
    // After
    server.httpUri();
    server.httpUri().resolve("/foo");
    
  • THttpService.allowedSerializationFormats() has been deprecated in favor of supportedSerializationFormats() for consistency with GrpcService. #2453
  • Service.decorate(Class) has been deprecated in favor of other decorate() methods that require a function.
  • ClosedPublisherException has been deprecated in favor of ClosedStreamException. #2468

☢️ Breaking changes

  • Most revamped APIs in this release were changed in a backward-incompatible way:
    • RequestLog
    • Attribute API in RequestContext
  • Content previewing mechanism has been revamped into decorators. Use ContentPreviewingClient and ContentPreviewingService.
  • You cannot add callbacks to RequestContext anymore because we found this feature results in poor performance and confusing behavior in many cases. We may want to revisit this feature if there is a valid use case for it.
  • {Server,VirtualHost}Builder.tls() methods do not throw an SSLException anymore. build() will throw an IllegalStateException instead. As a result, any SSL configuration failure will be known when a user calls build(), rather than tls().
  • We were not able to keep some classes or method signatures while we remove Http from class names.
  • ServiceRequestContext.logger() has been removed due to performance issues with Log4J2.
  • RequestContext.isTimedOut() has been removed.
  • We do not support Tomcat 8.0 anymore, which was obsoleted by Tomcat 8.5 anyway.
  • The classes in armeria-grpc-protocol have been reorganized into multiple packages.
  • Our Micrometer meter IDs have been changed, which means you might need to update your monitoring configuration. If you wish to switch back to the legacy naming style, specify the -Dcom.linecorp.armeria.useLegacyMeterNamed=true JVM option. However, please keep in mind this option will eventually go away, because the new naming convention is recommended by Micrometer.
  • All our methods do not return Optional anymore. They are all @Nullable now. If you wish to continue using Optional, just wrap the return value with Optional.ofNullable().
  • EndpointGroupRegistry has been removed, because you can now just specify an EndpointGroup directly when creating a client.
    • As a result, you need to specify an EndpointSelectionStrategy when building an EndpointGroup. If unspecified, EndpointSelectionStrategy.weightedRoundRobin() is used.
  • MeterIdPrefixFunction is not a functional interface anymore. You must implement two methods explicitly: activeRequestPrefix() and completeRequestPrefix().
  • Now that ClientFactory is a part of ClientOption, the following code will not work as expected, because options(options) will overwrite the factory.
    ClientOptions options = ClientOptions.builder().maxResponseLength(...).build();
    ClientFactory factory = ClientFactory.builder().useHttp2Preface(false).build();
    WebClient client = WebClient.builder(...)
                                .factory(factory)
                                .options(options)
                                .build();
    // This will fail!
    assert client.options().factory() == factory;
    
    To fix this, you must call options() first, and then override the individual properties:
    WebClient client = WebClient.builder(...)
                                .options(options)
                                .factory(factory)
                                .build();
    
  • StreamMessage.subscribe(..., boolean withPooledObjects) has been removed. Use subscribe(..., SubscriptionOption.WITH_POOLED_OBJECTS).
  • StreamMessage.drainAll(..., boolean withPooledObjects) has been removed. Use drainAll(..., SubscriptionOption.WITH_POOLED_OBJECTS).
  • HttpRequestDuplicator and HttpResponseDuplicator are now interfaces. Use HttpRequest.toDuplicator() and HttpResponse.toDuplicator() to create a duplicator.
  • StructuredLog and StructuredLoggingService have been removed. Use AccessLogWriter.
  • ThriftStructuredLogJsonFormat has been removed. Register ThriftJacksonModule to ObjectMapper to serialize or deserialize Thrift objects.

⛓ Dependencies

  • Brave 5.9.1 -> 5.9.3
  • Dropwizard 1.3.17 -> 1.3.18
  • Dropwizard Metrics 4.1.1 -> 4.1.2
  • gRPC 1.25 -> 1.27
  • Jackson 2.10.1 -> 2.10.2.20200130
  • java-jwt 3.8.3 -> 3.9.0
  • Jetty 9.4.24 -> 9.4.26
  • Micrometer 1.3.2 -> 1.3.3
  • Netty 4.1.43 -> 4.1.45
    • TCNative BoringSSL 2.0.26 -> 2.0.28
  • Prometheus Java client 0.8.0 -> 0.8.1
  • Reactor 3.3.1 -> 3.3.2
  • Retrofit 2.6.2 -> 2.7.1
  • RxJava 2.2.15 -> 2.2.17
  • SLF4J 1.7.29 -> 1.7.30
  • Spring Boot 2.2.1 -> 2.2.4, 2.1.10 -> 2.1.12
  • Thrift 0.12.0 -> 0.13.0
  • Tomcat 9.0.29 -> 9.0.30, 8.5.49 -> 8.5.50

🙇 Thank you

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

  • @4whomtbts
  • @abkura
  • @adriancole
  • @andrey-tpt
  • @anuraaga
  • @arhont375
  • @cbornet
  • @Charliocat
  • @cricket007
  • @Cronnay
  • @danada
  • @dylmeadows
  • @eonezhang
  • @franz1981
  • @geminiKim
  • @heowc
  • @hyangtack
  • @ikhoon
  • @ildartuykin
  • @imasahiro
  • @jcchavezs
  • @jrhee17
  • @KarboniteKream
  • @kezhenxu94
  • @kojilin
  • @linxGnu
  • @mauhiz
  • @max904-github
  • @mercanil
  • @minwoox
  • @monorisk
  • @njhill
  • @perlun
  • @renaudb
  • @rmichela
  • @sivaalli
  • @skkap
  • @snaiper80
  • @southernkasaist
  • @Stupremee
  • @syleeeee
  • @tobias-
  • @trustin
  • @ylgrgyq
armeria -

Published by trustin almost 5 years ago

💮 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

  • We now have a new immutable cookie API with SameSite attribute support, which replaces Netty's cookie API. #1567 #2286
    Cookie c1 = Cookie.of("foo", "bar")
    Cookie c2 = Cookie.builder("alice", "bob")
                      .domain("foo.com")
                      .path("/bar")
                      .maxAge(3600)
                      .sameSite("Strict")
                      .build();
    // Encoding
    ResponseHeaders resHeaders =
        ResponseHeaders.builder(HttpStatus.OK)
                       .add(HttpHeaderNames.SET_COOKIE,
                            Cookie.toSetCookieHeaders(c1, c2))
                       .build();
    // Decoding
    Cookies cookies = 
        Cookie.fromSetCookieHeaders(
            resHeaders.getAll(HttpHeaderNames.SET_COOKIE));
    
  • You can now replace the request headers of HttpRequest more conveniently using HttpRequest.withHeaders(RequestHeaders). #2278 #2283
    HttpRequest req = HttpRequest.of(HttpMethod.POST, "/post", 
                                     MediaType.PLAIN_TEXT_UTF_8,
                                     "Hello!");
    RequestHeaders newHeaders = RequestHeaders.of(HttpMethod.PUT, "/put",
                                                  MediaType.PLAIN_TEXT_UTF_8);
    HttpRequest newReq = req.withHeaders(newHeaders);
    
  • ServiceRequestContext.blockingTaskExecutor() is now a ScheduledExecutorService instead of ExecutorService, which means you can schedule delayed or periodic tasks. #2269
    // A service that sends `PING!` every second.
    HttpService service = (ctx, req) -> {
        HttpResponse res = HttpResponse.streaming();
        res.write(ResponseHeaders.of(200));
        AtomicReference<ScheduledFuture<?>> futureHolder = new AtomicReference<>();
        futureHolder.set(ctx.blockingTaskExecutor().scheduleWithFixedDelay(() -> {
            boolean success = res.tryWrite(HttpData.ofUtf8("PING!\r\n"));
            if (!success) {
                if (futureHolder.get() != null) {
                    futureHolder.get().cancel(false);
                }
            }
        }, 1, TimeUnit.SECONDS));
        return res;
    };
    
  • You can now add converters and exception handlers to annotated services more conveniently using the new fluent builder methods. #2242
    Server server =
        Server.builder()
              .annotatedService().requestConverters(converterA, converterB)
                                 .responseConverters(converterC, converterD)
                                 .exceptionHandlers(handlerA, handlerB)
                                 .build(myAnnotatedService)
              .build();
    
  • You can now configure how Armeria decides ServiceRequestContext.clientAddress() via ServerBuilder.clientAddressMapper(). #1631 #2294
    Server.builder()
          .clientAddressMapper(proxiedAddrs -> {
              InetSocketAddress srcAddr = proxiedAddrs.sourceAddress();
              List<InetSocketAddress> destAddrs = proxiedAddrs.destinationAddresses();
              if (destAddrs.isEmpty()) {
                  // No proxy servers involved.
                  return srcAddr;
              } else {
                  // When there are more than one proxy server involved,
                  // trust only the address given by the last proxy server.
                  return destAddrs.get(destAddrs.size() - 1);
              }
          });
    
  • You can now choose a different SLF4J Logger than the default one when using LoggingClient or LoggingService. #2220 #2237
    Logger myLogger = LoggerFactory.getLogger(MyService.class);
    Server server =
        Server.builder()
              .service("/",
                       myService.decorate(LoggingService.builder()
                                                        .logger(myLogger)
                                                        .newDecorator()))
              .build();
    
  • BraveClient now adds connection timing information to a span. #2271 #2273
    • connection-acquire.start and connection-acquire.end
    • dns-resolve.start and dns-resolve.end
    • socket-connect.start and socket-connect.end
    • connection-reuse.start and connection-reuse.end
  • withDeadlineAfter is now supported for gRPC client stubs. #2284
  • GrpcService now allows controlling whether to respect the "grpc-timeout" header sent by a gRPC client. #2284
    • Consider disabling this feature via GrpcServiceBuilder.useClientTimeoutHeader() in an insecure environment.
  • THttpService and ThriftCallService now supports adding more than one Thrift service at the same endpoint. #2164 #2285
    class MyFooService implements FooService.Iface ... {
        public void foo() { ... }
    }
    
    class MyBarService implements BarService.Iface ... {
        public void bar() { ... }
    }
    
    // "foo" call goes to MyFooService and
    // "bar" call goes to MyBarService.
    Server server =
        Server.builder()
              .service("/thrift",
                       THttpService.builder()
                                   .addService(new MyFooService())
                                   .addService(new MyBarService())
                                   .build())
              .build();
    
  • armeria-spring-boot-actuator-autoconfigure now supports the official CORS settings. #2063
    # application.yml
    management.endpoints.web.cors.allowed-origins: https://example.com
    management.endpoints.web.cors.allowed-methods: GET,POST
    

📈 Improvements

  • Improved routing performance. #2293 #2295
  • The core JAR file is now smaller, by removing unnecessary resources such as web fonts and favicons. #2299 #2300
  • HttpRequest.of(RequestHeaders, Publisher) now handles the case where the Publisher is actually an HttpRequest. #2278 #2283

🔒 Security fixes

🛠️ Bug fixes

  • The event loop threads are properly cleaned up when Server failed to start. #2288
  • Server now sends a redirect response correctly for the requests without a trailing slash (/) even when you bound a fallback service at prefix:/. #2116 #2292
  • Fixed a bug where routing cache did not work as expected, leading suboptimal routing performance. #2293
  • Annotated services now accept only the first "Cookie" header when injecting Cookies, because multiple "Cookie" headers must be prohibited according to RFC 6265. #2286
  • GrpcService now respects gRPC stub deadline. #2008 #2284

🏚️ Deprecations

  • Deprecated HttpRequest.of(HttpRequest, RequestHeaders) in favor of
    HttpRequest.withHeaders() #2283
  • Deprecated HttpRequest.of(AggregatedHttpRequest) and
    HttpResponse.of(AggregatedHttpResponse) in favor of
    AggregatedHttpRequest.toHttpRequest() and
    AggregatedHttpResponse.toHttpResponse(). #2283
    • These methods were removed from AggregatedHttpMessage some time ago due to ambiguity, but now we are reviving them because we have separate types for requests and responses.
  • Cookies.copyOf() has been deprecated in favor of Cookies.of(). #2286
  • AnnotatedServiceBuildingBuilder.requestConverter(), responseConverter() and exceptionHandler() have been deprecated in favor of requestConverters(), responseConverters() and exceptionHandlers() respectively. #2242
  • Sampler.rateLimited() has been deprecated in favor of rateLimiting(). #2122 #2289
  • THttpService.of() and ofFormats() factory methods that require a Map<String, ?> have been deprecated. Use THttpService.builder() and call THttpService.addService(String, Object) multiple times instead. #2285

☢️ Breaking changes

  • ServerBuilder.blockingTaskExecutor() now requires a ScheduledExecutorService instead of an ExecutorService. #2269
  • The behavior of automatic redirection for the case of missing trailing slash (/) has been changed (in a good way). #2116 #2292
    • For example, previously, when a client sent a request to /docs, the following server routed the request to TomcatService:
      Server server =
          Server.builder()
                .serviceUnder("/docs", new DocService())
                .serviceUnder("/", TomcatSerivce.forClassPath(...))
                .build();
      
    • However, from this release, the request will not be routed to TomcatService but the server will issue a redirect response to /docs/.
  • ProxiedAddresses class has been redesigned to handle the case of more than one intermediary proxy server. #1631 #2294
  • Cookies now uses Armeria's own Cookie. #2286
  • Cookies now may contain the cookies with the same name. #2286
    • Note that RFC does not prohibit duplicate names at all, so this is correct behavior.
  • Annotated services now accept only the first "Cookie" header when decoding cookies. Sending multiple "Cookie" headers was a violation of RFC 6265 anyway. #2286
  • The ThriftCallService factory method with signature of(Map<String, ? extends Iterable<?>>) has been changed to of(Map<String, ? extends Iterable<?>>) #2285

⛓ Dependencies

  • Brave 1.3.1
  • Jetty 9.4.22 -> 9.4.24
  • Micrometer 1.3.1 -> 1.3.2
  • Netty TCNative BoringSSL 2.0.27 -> 2.0.26
  • Project Reactor 3.3.0 -> 3.3.1
  • RxJava2 2.2.14 -> 2.2.15
  • Spring Boot 2.1.10 -> 2.2.1
  • Tomcat 9.0.27 -> 9.0.29, 8.5.47 -> 8.5.49

🙇 Thank you

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

  • @anuraaga
  • @chrsow
  • @heowc
  • @hyangtack
  • @ikhoon
  • @imasahiro
  • @JLLeitschuh
  • @JunoJunho
  • @magnuschatt
  • @minwoox
  • @monorisk
  • @renaudb
  • @sivaalli
  • @stypr
  • @tobias-
  • @trustin
armeria -

Published by trustin almost 5 years ago

💮 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();
    
  • 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();
    
  • 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:

  • @anuraaga
  • @delegacy
  • @eunchan-kim
  • @heowc
  • @hirakida
  • @ikhoon
  • @imasahiro
  • @jrhee17
  • @jyblue
  • @matsumana
  • @mauhiz
  • @minwoox
  • @rmohta
  • @sivaalli
  • @snaiper80
  • @Stupremee
  • @trustin
  • @yanghun0070
Package Rankings
Top 5.13% on Repo1.maven.org
Related Projects