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
Bot releases are hidden (Show)
Host
header to populate serverName
and serverPort
, like Tomcat doesTomcatService
and fix JettyService
to follow Servlet spec where request URI is decodedWarning: This release contains a lot of breaking changes. Read this release note carefully.
TomcatService
support Tomcat 8.5ServerBuilder.decorator()
that adds a decorator to all services in a serverVirtualHostBuilder.decorator()
that adds a decorator too all services in a VirtualHost
Having trouble with migration? Please feel free to ask us questions by creating a new issue or joining our Slack channel.
If you did not extend any classes in Armeria, you may be able to migrate relatively easily.
Future
anymore but CompletableFuture
. e.g. Server.start()
and stop()
ThriftService
with THttpService
.HttpClient
in favor of SimpleHttpClient
.If you implemented any interfaces or extended any types provided by Armeria or you still have issues with migration, please read on.
Previously, Armeria buffered full request and response in memory. It means it was not able to consume or produce a stream of large content. It also could not start processing HTTP headers until the complete HTTP content is received, which may affect latency negatively.
We chose Reactive Streams API as the foundation of HTTP content streaming because it is the de-facto standard API for implementing object streaming these days; RxJava, gRPC, Akka and Project Reactor are the notable adoptors.
Please watch Roland Kuhn's slides to learn more about Reactive Streams.
Armeria defines a new interface called com.linecorp.armeria.common.reactivestreams.RichPublisher
which adds a few useful operations on top of org.reactivestreams.Publisher
and uses it wherever potentially large stream is expected. com.linecorp.armeria.common.http.HttpRequest
and HttpResponse
are good examples that extend RichPublisher<HttpObject>
.
Armeria also provides an additional interface called com.linecorp.armeria.common.reactivestreams.Writer
, which is useful when you write a hot (or active) publisher in a reactive way:
// Not OK: We will see OutOfMemoryError!
Writer<HttpObject> out = ...;
for (;;) {
out.write(httpContent);
}
// OK: The callback we specified with onDemand() is executed only when
// the subscriber has demanded more HttpObjects.
void produceTraffic(Writer<HttpObject> out) {
out.write(httpContent);
out.onDemand(() -> produceTraffic(out));
}
produceTraffic(out);
io.netty.util.concurrent.Future
and Promise
has been replaced with CompletableFuture
.io.netty.buffer.ByteBuf
io.netty.handler.codec.http.HttpRequest
, HttpResponse
, HttpContent
and many related message types
io.netty.handler.codec.http.HttpHeaders
io.netty.handler.codec.http.HttpHeaderNames' and
HttpHeaderValues`io.netty.handler.codec.http.HttpResponseStatus
and HttpStatusClass
io.netty.handler.codec.http.FullHttpRequest
and FullHttpResponse
AsciiString
as header names because it's generic enough.Taking advantage of all the breaking changes introduced in this release, we designed our new HTTP API fit better with HTTP/2 than HTTP/1. Armeria will convert the inbound HTTP/1 messages to HTTP/2 automatically before they are served by your HTTP service or client implementation.
Previously, we shared one context type for both client and server side: ServiceInvocationContext
. This is potentially confusing and both client and server sides had to shoehorn their models into the common model provided by ServiceInvocationContext
.
Also, ServiceInvocationContext
assumed that a request is fully available when context is created. However, this is not true anymore with content streaming.
ServiceInvocationContext
with com.linecorp.common.RequestContext
ClientRequestContext
and ServiceRequestContext
which extend RequestContext
RESPONSE_TIMEOUT_MILLIS
to DEFAULT_RESPONSE_TIMEOUT_MILLIS
RequestLog
and ResponseLog
so that a client or a service fills the properties as they are available. A user will be notified via RequestContext.requestLogFuture()
and responseLogFuture()
when all necessary information is ready.RequestContext.method()
property always returns the method at the session layer. That is, in a Thrift-over-HTTP call, ctx.method()
will not return "someThriftMethod"
anymore but only return "POST"
because such information is available only when the full request has been received. You can get the Thrift method name from RequestLog
later when it's ready.LogCollectingService
and its subtypes for real-world examples.com.linecorp.armeria.server.Service
has been revamped:
Service
now has type parameters.ServiceCodec
and ServiceInvocationHandler
has been merged into Service
.Service.serve(ServiceRequestContext, Request)
serves a client request.com.linecorp.armeria.client.Client
has been revamped:
Client
now has type parameters.ClientCodec
and RemoteInvoker
have been merged into Client
.Client.execute(ClientRequestContext, Request)
executes an invocation.HttpService
with the new APIPreviously, HttpService
assumed a request is fully available when it is invoked, which is not true anymore.
HttpService
is now an interface, and we added AbstractHttpService
which replaces the old HttpService
class.
ThriftService
with the new APIThriftService
had tight coupling with HTTP session layer and we wanted to remove that.
ThriftService
has been deprecated; use THttpService
instead.
THttpService
, however, behind the scene, serving a Thrift call is achieved by two Service
s now: THttpService
and ThriftCallService
:
THttpService
translates an HTTP request into a ThriftCall
and a ThriftReply
into an HTTP response. (similar to ServiceCodec
which has been removed in this release)ThriftCallService
delegates a ThriftCall
to a stub implementation. (similar to ServiceInvocationHandler
which has been removed in this release)
ThriftCallService
are not HttpRequest
and HttpResponse
anymore but ThriftCall
and ThriftReply
.RemoteInvoker
to/with ClientFactory
RemoveInvokerOptions
, RemoteInvokerOption
and RemoteInvokerOptionValue
to SessionOptions
, SessionOption
and SessionOptionValue
RemoteInvokerOption.MAX_CONTENT_LENGTH
has been moved and renamed to ClientOption.DEFAULT_MAX_RESPONSE_LENGTH
and can be overridden via ClientRequestContext.setMaxResponseLength()
.ClientOption.RESPONSE_TIMEOUT_MILLIS
and WRITE_TIMEOUT_MILLIS
have been renamed to DEFAULT_RESPONSE_TIMEOUT_MILLIS
and DEFAULT_WRITE_TIMEOUT_MILLIS
and can be overridden via ClientRequestContext.setResponseTimeoutMillis()
and setWriteTimeoutMillis()
.Previous client composition and decoration was based on the assumption that the full request content is available upon its invocation, which isn't true anymore.
DECORATOR
with DECORATION
whose value type is ClientDecorations
ClientFactory
will apply the decorator at the right place in the invocation chain:
builder.add(ThriftCall.class, ThriftReply.class, thriftCallDecorator);
builder.add(HttpRequest.class, HttpResponse.class, httpDecorator);
SimpleHttpClient
and its related types exposed Netty API in its public API and it wasn't powerful enough for daily use. This release introduces a new client interface called HttpClient
and deprecates SimpleHttpClient
.
LoggingClient/Service
and MetricCollectingClient/Service
MetricConsumer
to MessageLogConsumer
metrics
package to the logging
packageLogCollectingClient/Service
LoggingClient/Service
and MetricCollectingClient/Service
extends LogCollectingClient/Service
MetricCollectingClient/Service
to DropwizardMetricCollectingClient/Service
because a user can extend LogCollectingClient/Service
to support his or her favorite metric collecting libraryDocService
ClassCastException
at TTextProtocol.readStructBegin()
when reading an ailased enum.DocService
TTextProtocol.reset()
activeRequests
if you are using DropwizardMetricConsumer
.DocService
DocService
will provide the comments in the IDL files if you put the .json
files produced by the nightly build of the official Thrift compiler into the META-INF/armeria/thrift
directory.JettyService
VirtualHost.defaultHostname()
and Server.defaultHostname()
Server.defaultHostname()
to get the hostname of your machine reliably.TomcatService.forConnector()
does not require hostname anymore thanks to this new feature.TomcatService
does not call Server.destroy()
when it stops.IdleStateEvent
to suppress misleading 'unexpected user event' message.HEAD / HTTP/1.1
upgrade request for H1C-to-H2C upgrade by default again.com.linecorp.armeria.defaultUseHttp2Preface
to true
.NB: This breaks the API backward compatibility of the newDropwizardDecorator()
method.
// Before:
MetricCollectingClient.newDropwizardDecorator("serviceName", registry);
MetricCollectingService.newDropwizardDecorator("serviceName", registry);
// After:
import static com.codahale.metrics.MetricRegistry.name;
MetricCollectingClient.newDropwizardDecorator(registry, name("client", "serviceName"));
MetricCollectingService.newDropwizardDecorator(registry, name("server", "serviceName"));
SessionProtocolNegotiationException
when protocol upgrade fails due to timeoutDocService
PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
for h1c-to-h2c upgrade
HEAD / HTTP/1.1
requests can cause unexpected load on an Armeria server if a user bound a service at /
and the service does not handle the HEAD
method specially.RemoteInvokerOption.USE_HTTP2_PREFACE
option to false
. You can also change the default value of this option from true
to false
by setting the system property com.linecorp.armeria.defaultUseHttp2Preface
to `false./dev/epoll
or OpenSSL