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)
A user can customize how Armeria handles duplicate path mappings via ServerBuilder.rejectedPathMappingHandler(RejectedPathMappingHandler)
. #1283 #1298
ServerBuilder sb = new ServerBuilder();
sb.rejectedPathMappingHandler((virtualHost, mapping, existingMapping) -> {
// Do nothing.
});
sb.service("/", ...);
sb.service("/", ...); // Ignored silently.
A user can now specify alternative responses for authorization success and failure when building an HttpAuthService
using HttpAuthServiceBuilder
. #506
HttpAuthService authService = new HttpAuthServiceBuilder()
.addBasicAuth(...)
.onSuccess((delegate, ctx, req) -> HttpResponse.of(200))
.onFailure((delegate, ctx, req, cause) -> HttpResponse.of(401))
.build();
A user can now build a composite Authorizer
from more than one Authorizer
s. #1303
Authorizer<HttpRequest> a = ...;
Authorizer<HttpRequest> b = ...;
Authorizer<HttpRequest> c = ...;
Authorizer<HttpRequest> composite = a.orElse(b).orElse(c);
Added EventLoopRule
and EventLoopGroupRule
for easier setup and tear-down of EventLoop
and EventLoopGroup
in a JUnit test case. #1304
public class MyTest {
@ClassRule
public static final EventLoopRule eventLoop = new EventLoopRule();
@Test
public void runTask() {
eventLoop.get().execute(() -> System.err.println("Hello!"));
}
}
Added RequestContext.executor()
and RequestContext.contextAwareExecutor()
for potentially easier mocking of RequestContext
#1307
The frontend-side implementation of DocService
has been rewritten with React, TypeScript and Material UI. #654 #1288
A user can now inject an arbitrary JavaScript string into DocService
pages. It is also possible to inject example HTTP headers of DocService
using JavaScript. This can be useful if you need to set the access token retrieved from browser's local storage to the example HTTP headers or to inject some analytics code. #1312
For example, a Firebase auth user would just add the following injected script to have debug requests automatically authenticated with a valid access token:
armeria.registerHeaderProvider(function() {
return firebase.auth().currentUser.getIdToken()
.then(token => { authorization: 'Bearer ' + token });
});
Added a new system property com.linecorp.armeria.maxNumConnections
so that a user can change the default max number of allowed server-side connections. The default value stays unchanged as Integer.MAX_VALUE
. #1309
Retrofit client now supports HTTP response streaming, as well as waiting for the complete content. Streaming is disabled by default because there's no way to stream a response in a fully asynchronous manner in Retrofit (i.e. blocking calls will be involved). Use ArmeriaRetrofitBuilder.streaming(boolean)
to enable this feature. #1296
HealthCheckedEndpointGroup
does not raise an unexpected exception anymore when there are duplicate endpoints to check. #1290Endpoint.toString()
does not include an IP address. #1299RequestLog
does not contain gRPC request parameters and return values. #1308
RequestLog
does not reach COMPLETE
availability for some edge cases. #1308HttpAuthService
is now final
. Use HttpAuthServiceBuilder
for its customization. #1303Changed the default behavior to leave a warning log when creating an annotated service with redundant use of Optional
and @Default
#1284:
// No need to use Optional because 'value' is always present.
@Get("/foo/:value")
public String foo(@Param Optional<String> value) {}
// No need to use @Default because 'value' is always present.
@Get("/bar/:value")
public String bar(@Param @Default("defVal") String value) {}
// Optional and @Default were used together. 'value' will always be present.
@Get("/baz")
public String baz(@Param @Default("defVal") Optional<String> value) {}
Added RequestContext.push()
which deprecates RequestContext.push(RequestContext)
#1266
// Before:
try (SafeCloseable ignored = RequestContext.push(ctx)) { ... }
// After:
try (SafeCloseable ignored = ctx.push()) { ... }
Added RequestContext.pushIfAbsent()
which raises an IllegalStateException
if the caller attempts to push a new context when there's already another context set #1266
IllegalStateException
when contexts are set incorrectly. #1266RequestContext.push(RequestContext)
has been deprecated in favor of RequestContext.push()
. #1266MeterIdPrefixFactory.activeRequestsPrefix()
which is dedicated to generating MeterIdPrefix
for active request counter gauges. #1258 #1260
httpStatus
, which makes sense only for MeterIdPrefixFactory.apply()
.CompletionStage
instead of CompletableFuture
so that a user does not have to call CompletionStage.toCompletableFuture()
. #1237
CircuitBreakerStrategy
RetryStrategy
ThrottlingStrategy
LoggingDecorator
now logs the request of a failed response for easier diagnosis. #1244application/grpc+proto
media type. #1245EndpointSelectionStrategy.WEIGHTED_ROUND_ROBIN
by reducing the time complexity from O(N * W)
to O(log(N))
, where N is the number of endpoints and W is the maximum weight. #1248TomcatService
so that managed Tomcat
instances and unmanaged instances are handled separately. #1249armeria-retrofit2
. #1250RetryingClient
, the Exception
of the last retry attempt was not propagated in a certain case. #1234RequestLog
now contains all the necessary pseudo headers such as :authority
and :status
so that loggers do not see unexpected null
s that make log processing complicated. #1235RetryingClient
did not stop when ClientFactory
is closed. #1236RetryingClient
did not stop when StreamMessage
is aborted. #1242ServerBuilder
now rejects duplicate path mappings to prevent a user mistake of binding more than one Service
at the same path mapping. #529 #1247HttpClient
connected to a wrong host when custom authority is used. #1251100 Continue
response when Expect: 100-continue
header exists in a request. #1255MeterIdPrefixFunction
does not add an httpStatus
tag to active request count gauges anymore. #1258 #1260TomcatService
and Spring Boot #1249RequestLog.host()
has been deprecated in favor of RequestLog.authority()
. #1235RetryGiveUpException
has been removed. #1234TomcatService.connector()
now returns Optional<Connector>
instead of Connector
. #1249Added more methods related with accessing the IP address of an Endpoint
. #1232
assert Endpoint.of("example.com").hasIpAddr() == false;
assert Endpoint.of("example.com").withIpAddr("1.2.3.4").hasIpAddr() == true;
assert Endpoint.of("1.2.3.4").isIpAddrOnly() == true;
assert Endpoint.of("::1").ipFamily() == StandardProtocolFamily.INET6;
Endpoint
with an IP address is not handled correctly. #1230 #1233
HttpHealthCheckedEndpointGroup
to send a health check request to a wrong IP address if a host name has multiple IP addresses, especially when used with DnsAddressEndpointGroup
.Added ServerBuilder.channelOption()
and childChannelOption()
so that a user can specify Netty ChannelOption
s. #1009 #1189
ServerBuilder sb = new ServerBuilder();
sb.channelOption(ChannelOption.SO_BACKLOG, true);
sb.channelOption(ChannelOption.SO_REUSEADDR, true);
sb.childChannelOption(ChannelOption.SO_RCVBUF, 1048576);
sb.childChannelOption(ChannelOption.SO_SNDBUF, 1048576);
Added ServiceRequestContext.additionalResponseHeaders()
and ClientRequestContext.additionalRequestHeaders()
so that a user can specify the additional HTTP headers to send when writing a request or a response. This feature is useful especially for RPC services such as THttpService
. #992 #1225
public class MyThriftServiceImpl implements MyThriftService.AsyncIface {
@Override
public void someServiceMethod(MyThriftRequest req,
AsyncMethodCallback<MyThriftResponse> callback) {
final ServiceRequestContext ctx = RequestContext.current();
ctx.setAdditionalResponseHeader(HttpHeaderNames.of("my-custom-header"),
"my-custom-value");
...
}
}
You can inject multi-value HTTP headers into a List
or similar parameter in annotated services. #1025 #1191
public class MyAnnotatedService {
@Post("/post")
public void post(@Header("item-id") List<Integer> itemIds) { ... }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
You can nest @RequestObject
annotation in annotated services. #1175 #1191
public class MyAnnotatedService {
@Post("/post")
public void post(@RequestObject MyBean bean) { ... }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
}
public class MyBean {
public MyBean(@Param Integer foo, @Header String bar,
@RequestObject MyNestedBean nestedBean) { ... }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
public class MyNestedBean { ... }
You can inject HTTP cookies into a new dedicated type Cookies
in annotated services. #1222
public class MyAnnotatedService {
@Post("/post")
public void post(Cookies cookies) {
// ^^^^^^^^^^^^^^^
for (Cookie c : cookies) {
System.err.println(c.name() + " = " + c.value());
}
}
}
Added various default ResponseConverterFunction
implementations for convenient JSON, text and binary response generation in annotated services. #1221
public class MyAnnotatedService {
@Get("/json")
@ProducesJson // Shortcut of @Produces("application/json; charset=utf-8")
public MyBean getJson() {
/* ... MyBean will be converted into a JSON document by Jackson ... */
}
}
@Produces
, @Consumes
and their various shortcut annotations such as @ProducesJson
and @ConsumesJson
for convenient media type negotication, consumption and production. See Media type negotiation for more information.DistributionStatisticConfig
so that Micrometer Timer
s and DistributionSummary
s to have sensible settings. We increased the precision of the percentile values and made the histogram buckets are rotated every minute rather than every 40 seconds. #1226DynamicEndpointGroup
and its subtypes notify their listeners even when the Endpoint
list did not change. We also now sort the Endpoint
list. #1216 #1220armeria-tomcat8.5
JAR did not contain any files. #1218ClientFactoryBuilder.socketOption()
has been deprecated in favor of channelOption()
, so that its naming is consistent with ServerBuilder.channelOption()
. #1228@ProduceType
and @ConsumeType
have been deprecated in favor of @Produces
and @Consumes
. #1221status
tag produced by the function returned by MeterIdPrefixFunction.ofDefault()
has been renamed to httpStatus
for clarity. #1215 #1219ClientRequestContext.HTTP_HEADERS
attribute has been removed. Use ClientRequestContext.additionalRequestHeaders
#1225An annotated service can now inject multiple HTTP headers into List<String>
, Set<String>
or Iterable<String>
. #1164
public class MyAnnotatedService {
// The values of 'x-delete-options` are injected into 'xDeleteOptions'.
@Delete("/users/:userId")
public void deleteUser(@Param String userId, @Header List<String> xDeleteOptions) {
...
}
}
Added PrometheusRegistries.defaultRegistry
#1171 #1181
// Before
PrometheusMeterRegistry r = PrometheusRegistries.newRegistry(CollectorRegistry.defaultRegistry);
// After
PrometheusMeterRegistry r = PrometheusRegistries.defaultRegistry;
Made the Timer
s and DistributionSummary
s created by Armeria customizable. #1170 #1176
MoreMeters.setDistributionStatisticConfig(
DistributionStatisticConfig.builder()
.percentiles(/* custom percentiles */)
.expiry(/* custom expiry */)
.build());
MeterIdPrefixFunction.ofDeault()
now adds the status
tag to meter IDs. #1172
Added the setters for ExceptionHandlerFunction
, RequestConverterFunction
and ResponseConverterFunction
to AnnotatedServiceRegistrationBean
. #1141 #1173
Added more decorator setters to all *ServiceRegistrationBean
s. #1080 #1174
Added the access log format tokens for logging the properties of RequestLog
. #1195
You can now customize the timestamp format in access log. #1195
You can now customize how CircuitBreakerClient
determines whether a request was successful or not. #1192
Added a new service type called TransientService
, the requests handled by it is not taken into account during graceful shutdown. #1196
Added a new unsafe gRPC client option GrpcClientOptions.UNSAFE_WRAP_RESPONSE_BUFFERS
. #1204
Added a new module armeria-rxjava
which provides a plugin for RxJava 2. By enabling this plugin, your RxJava functions will always be invoked with thread-local RequestContext
set. #1194
RequestContextAssembly.enable();
Added a new module armeria-tomcat8.5
for Tomcat 8.5 users. #1212
Added more convenience methods to HttpData
. #1188 #1214
HttpData.toInputStream()
HttpData.toReader()
HttpData.toReaderUtf8()
HttpData.toReaderAscii()
CompositeByteBuf
allocation in gRPC. #1167CorsService
is now compatible with Internet Explorer. #1186NullPointerException
when an annotated service method returns void
. #1165 #1166NoClassDefFoundError
in armeria-spring-boot*
when armeria-thrift
is not added to the dependencies. #650 #1182DropwizardMeterRegistry
, because the monitoring systems based on Dropwizard Metrics would prefer using the distribution stats provided by Dropwizard Histogram
and Timer
. #1190HealthCheckService
do not hinder timely graceful shutdown anymore. #1196MoreMeters.summaryWithDefaultQuantiles()
and timerWithDefaultQuantiles()
have been deprecated. Use MoreMeters.newDistributionSummary()
and newTimer()
. #1176*ServiceRegistrationBean.setDecorator()
has been deprecated. Use setDecorators()
. #1174MeterIdPrefixFunction.ofDefault()
now adds the status
tag. Adjust your metric collection and monitoring system accordingly. #1172CircuitBreakerClient
is now an abstract class. Use CircuitBreakerHttpClient
or CircuitBreakerRpcClient
. #1192CircuitBreakerBasedThrottlingStrategy
has been removed without an alternative. See #1209 for rationale.status
tag added by the function returned by MeterIdPreficFunction.ofDefault()
to httpStatus
in our next release.Added more concise variants of HttpResponse.of()
#1142
// Defaults to HttpStatus.OK and MediaType.PLAIN_TEXT_UTF_8.
HttpResponse.of("Hello, world!");
HttpResponse.of("Hello, %s!", name);
// Defaults to HttpStatus.OK.
HttpResponse.of(MediaType.PLAIN_TEXT_UTF_8, "Hello, world!");
HttpResponse.of(MediaType.PLAIN_TEXT_UTF_8, "Hello, %s!", name);
@Param
and @Header
annotations can be used without value if an annotated service class was compiled with -parameters
option. #570 #1147
// Before
public class MyAnnotatedService {
@Get("/get/:item")
public String getItem(@Param("item") item) { .. }
// ~~~~~~~~~~~~~~~~~~~ Have to type 'item' twice.
}
// After
public class MyAnnotatedService {
@Get("/get/:item")
public String getItem(@Param item) { .. }
// ~~~~~~~~~~~ No need to type 'item' twice.
}
A user can define his or her own decorator annotation instead of using @Decorator
annotations. #1010 #1149
Added @LoggingDecorator
and @RateLimitingDecorator
for a demonstrative purpose.
public class MyAnnotatedService {
@Get("/get/:product")
@LoggingDecorator(successfulResponseLogLevel = LogLevel.INFO, samplingRate = 0.75f)
@RateLimitingDecorator(1000.0f) // Up to 1000 req/s
public String getProduct(@Param product) { .. }
}
See Decorating an annotated service with a custom decorator annotation for more information.
armeria-zookeeper
has been revamped to use Curator instead of vanilla ZooKeeper. #882 #1007 #1035 #1044
ZooKeeperUpdatingListenerBuilder
to expose more configuration parameters.Revamped DNS-based service discovery. #1088 #1148
DnsTextEndpointGroup
which retrieves the endpoint list from TXT
DNS records.DnsAddressEndpointGroupBuilder
, DnsServiceEndpointGroupBuilder
and DnsTextEndpointGroupBuilder
to provide more configuration properties.EndpointGroup
implementations now respec the TTL values returned by a DNS server, rather than sending a DNS query per second.HttpAuthService
can be configured to use a non-standard header to extract authentication tokens. #1132
ServerBuilder sb = new ServerBuilder();
sb.service("/my_service",
myService.decorate(new HttpAuthServiceBuilder()
.addBasicAuth(myAuthrorizer, HttpHeadersNames.of("my-custom-header"))
.newDecorator()));
The access log writer implementations provided by AccessLogWriters
logs RPC method name as a URI fragment. #1157
Added SSLeay PKCS#5 private key format support. #1144
NodeValueCodec
when creating a ZooKeeperUpdatingListener
. #1035DocService
did not detect the GrpcService
bound with ServerBuilder.service(ServiceWithPathMappings)
correctly. #1136 #1138ZooKeeperUpdatingListener
and ZooKeeperEndpointGroup
have been refactored heavily with some factory methods removed. #1044DnsAddressEndpointGroup
and DnsServiceEndpointGroup
have been refactored heavily with some factory methods removed. #1148HttpHeaders.contentType()
returns an outdated value.armeria-spring-boot-*
has been renamed to armeria-spring-boot1-*
and armeria-spring-boot2-*
has been renamed to armeria-spring-boot-*
for artifact naming consistency.
armeria-spring-boot-*
armeria-spring-boot1-*
Http(Request|Response).aggregateWithPooledObjects()
, which does the same job with aggregate()
except that it uses ByteBufHttpData
for aggregation.
aggregate()
in most cases.AbortedStreamException
and ClosedChannelException
will be suppressed so that they do not produce noisy log messages.StreamWriter.write()
will throw ClosedPublisherException
instead of IllegalStateException
from this release.ByteBufHttpData
StreamMessageDuplicator.close()
, which affects RetryingClient
ClosedPublisherException
instead of IllegalStateException
when StreamWriter.write()
fails#1049 Spring Boot 2 support
armeria-spring-boot2-autoconfigure
or armeria-spring-boot2-autoconfigure-shaded
.#1066 #1096 Parameter and header injection into bean property and constructor for annotated services. See the official documentation for more information.
public class FinderService {
@Get("/find/:id")
public String find(@RequestObject FindRequest req) { ... }
}
// Using constructor
public class FindRequest {
public FindRequest(@Param("id") String id, @Header("x-type") String type) {
this.id = id;
this.type = type;
}
...
}
// Using fields
public class FindRequest {
@Param("id") private String id;
@Header("x-type") private String type;
}
// Using setters
public class FindRequest {
public void setId(@Param("id") String id) { ... }
public void setType(@Header("x-type") String type) { ... }
}
// Using multi-field setters
public class FindRequest {
public void setAll(@Param("id") String id, @Header("x-type") String type) { ... }
}
#1085 Easier self-signed TLS certificate generation with ServerBuilder.tlsSelfSigned()
, which may be very useful for testing
ServerBuilder sb = new Serverbuilder();
sb.https(8443);
sb.tlsSelfSigned();
#1087 #1089 Endpoint.ipAddr()
, which allows specifying an IP address explicitly for an Endpoint
. This is a preparatory work for providing better DNS-based service discovery.
#1090 MoreNamingConventions.configure()
, which configures a Micrometer MeterRegistry
to use our better naming convention
#1099 #1100 #1101 PROXY protocol support, which is useful when you are behind a load balancer such as HAProxy and AWS ELB
ServerBuilder sb = new ServerBuilder();
sb.port(8080, SessionProtoxol.PROXY, SessionProtocol.HTTP);
#1099 #1100 #1101 Ability to serve HTTP and HTTPS on the same port
ServerBuilder sb = new ServerBuilder();
sb.port(8888, SessionProtoxol.HTTP, SessionProtocol.HTTPS);
// You can even enable PROXY protocol support, too.
sb.port(9999, SessionProtoxol.PROXY, SessionProtocol.HTTP, SessionProtocol.HTTPS);
ByteBufHttpData
StreamMessageDuplicator.close()
, which affects RetryingClient
armeria.server.numConnections
to armeria.server.connections
PRI * HTTP/2.0
first when the URI scheme is http
, in lieu of sending the HTTP/1 upgrade request HEAD / HTTP/1.1
.
-Dcom.linecorp.armeria.defaultUseHttp2Preface=false
JVM option or use ClientFactoryBuilder.useHttp2Preface(false)
to go back to the old behavior.#1004 ServerListenerBuilder
which allows functional composition of Runnable
s and Consumer
s for building a ServerListener
ServerBuilder sb = new ServerBuilder();
sb.serverListener(new ServerListenerBuilder()
.addStartingCallback(server -> { ... })
.addStoppingCallback(server -> { ... })
.build());
#1018 Allow session protocol to be specified for HttpHealthCheckedEndpointGroup
.
HttpHealthCheckedEndpointGroup healthCheckedGroup =
new HttpHealthCheckedEndpointGroupBuilder(delegateGroup, "/internal/l7check")
.protocol(SessionProtocol.HTTPS)
.retryInterval(Duration.ofSeconds(5))
.build();
#1050 #1051 More concise server port and TLS configuration in ServerBuilder
ServerBuilder sb = new ServerBuilder();
// Before
sb.port(8080, SessionProtocol.HTTP);
sb.port(8443, SessionProtocol.HTTPS);
sb.sslContext(SessionProtocol.HTTPS, keyCertChainFile, keyFile);
// After
sb.http(8080);
sb.https(8443);
sb.tls(keyCertChainFile, keyFile);
#1056 RetryStrategy.onStatus()
now accepts a BiFunction<HttpStatus, Throwable, Backoff>
so that a user can handle both response status and exception.
HttpClient client = new HttpClientBuilder("http://example.com/")
.decorator(RetryingHttpClient.newDecorator(
RetryStrategy.onStatus((status, cause) -> {
if (cause != null) {
return backoffA;
}
if (status.codeClass() == HttpStatusClass.SERVER_ERROR) {
return backoffB;
}
return null; // Do not retry.
}));
.build();
#1058 Add more server-side metrics:
armeria.server.numConnections
- the number of open connectionsarmeria.server.pendingResponses
- the number of pending responses during graceful shutdown:authority
header when sending a request.DocService
does not recognize a prefix-mapped THttpService
.ThrottlingService
does not work with RpcResponse
.MeterIdPrefixFunction.ofDefault()
doesn't collect service level metrics for unframed gRPC requestsRetryStrategy.on*Status()
should allow retry on exceptions rather than just HTTP status.@Nullable
annotations throughout the APIConcurrentModificationException
in DefaultKeyedChannelPool.doClose()
StreamMessageDuplicator
to the subscriber.HttpHealthCheckedEndpointGroup
have been deprecated. Use the of()
factory methods or HttpHealthCheckedEndpointGroupBuilder
.ServerBuilder.port()
methods have been deprecated. Use Server.http()
or https()
.ServerBuilder.sslContext()
methods have been deprecated. Use ServerBuilder.tls()
.ZooKeeperEndpointGroup.Mode
. Mode.IN_NODE_VALUE
was broken by design, which leaves only Mode.IN_CHILD_NODES
.RetryStrategy.onStatus()
now accepts BiFunction<HttpStatus, Throwable, Backoff>
instead of Function<HttpStatus, Backoff>
. See the 'New features' section above for more information.PropertiesEndpointGroup
without default port number.
You do not need to specify the defaultPort
parameter when your endpoints' default ports are 80 or 443.
final Properties props = new Properties();
props.setProperty("myHosts.0", "foo.com");
props.setProperty("myHosts.1", "bar.com");
final PropertiesEndpointGroup group = PropertiesEndpointGroup.of(props, "myHosts");
assert group.endpoints().contains(Endpoint.of("foo.com"));
assert group.endpoints().contains(Endpoint.of("bar.com"));
#774 #945 RedirectService
which sends a redirect response.
ServerBuilder sb = new ServerBuilder();
sb.service("/foo/{bar}", new RedirectService("/{bar}/foo"));
sb.service("regex:^/old-location/(?<path>.*)$",
new RedirectService("/new-location/{path}"));
#852 We now provide Maven BOM (Bill of Materials).
#935 #949 Annotated services now support enum
parameter types.
ServerBuilder sb = new ServerBuilder();
sb.annotatedService(new Object() {
@Get("/users/by_type/{userType}")
public AggregatedHttpMessage listUsersByType(@Param("userType") UserType userType) { ... }
});
public enum UserType {
ADMIN, MODERATOR, MEMBER
}
#943 #979 All packages are now annotated with NonNullByDefault
annotation so that Armeria is more friendly to the compilers and IDEs that understand JSR305 annotations, such Kotlin and IntelliJ IDEA.
For Kotlin, add -Xjsr305=strict
or -Xjsr305=true
compiler option, e.g.
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
}
}
#954 PropertiesEndpointGroup
which loads the endpoint list from a .properties
file or a Properties
Properties props = new Properties();
props.put("example.hosts.0", "example1.com");
props.put("example.hosts.1", "example2.com:8080");
props.put("example.hosts.2", "example3.com:9080");
EndpointGroup myGroup = PropertiesEndpointGroup.of(props, "example.hosts", 80);
#965 Add a dangerous option to use ByteBufHttpData
for incoming data in gRPC, which yields better throughput when payload is large
#967 #981 A Service
now has more control over the path cache via Service.shouldCachePath()
.
public class MyService implements HttpService {
@Override
public boolean shouldCachePath(String path, @Nullable String query, PathMapping pathMapping) {
// Always cache the path.
return true;
}
...
}
UnframedGrpcService
implements ServiceWithPathMappings
RequestLog
prioritizes an RPC response exception over a stream exception.ByteBufHttpData
instead of DefaultHttpData
for fewer memory copies.Class.isAssignableFrom()
in annotated servicesClientFactory.close()
does not close all connections.