0.42.0
Overview
This is a major ServiceTalk feature release appropriate for all users containing numerous new features and many improvements. We are actively working towards ServiceTalk 1.0 and this intermediate release helps us to refine and stabilize the API. Existing ServiceTalk applications will need to be recompiled to use the 0.42 release and will likely require some code changes or migration to the new API. Also, make sure all other libraries or extensions that depends on the ServiceTalk API in your classpath are also recompiled with 0.42.
Changes
The 0.42.0 release includes significant new features and API changes but incorporates as closely as possible the same dependencies and bug fixes as the prior 0.41.12 release.
Offloading Changes
In addition to the API changes, ServiceTalk 0.42 includes some significant behavioral differences that may impact existing applications. Offloading, the execution of user code on non-I/O threads, is one area that has changed significantly. In ServiceTalk 0.41 and earlier the strategy used for offloading was applied more generally than in 0.42. This meant that most user code, even code which did not expect to be offloaded, was offloaded from I/O threads. This approach had the advantages of consistency and safety; the execution environment for user code was predictable and the Netty I/O threads were protected from being unavailable while executing application code.
In ServiceTalk 0.42 the offloading strategy is more focused and offloading is done in fewer situations, primarily only those situations which explicitly require offloading. Offloading is an expensive activity. If the application or ServiceTalk logic which needs to be executed is insignificant or carefully bounded and never blocks then avoiding offloading has a positive impact on both latency and throughput. Offloading is controlled by the use of the publishOn
and subscribeOn
offloading operators and for filters and services by implementing the StrategyInfluencer
interface.
Executors and other operators
In prior versions of ServiceTalk all operators could access the most recently referenced Executor
in the operator pipeline. In 0.42 the intended executor for executing the operations pipeline is only exposed to offloading operators. Other operators are effectively “immediate” meaning that they expect to run on whatever thread is active when they are invoked, the timeout
and liftAsync
operators are affected.
Retrying / Auto-Retrying filters
RetryingHttpRequesterFilter & Auto-Retrying filters/API were unified in a new RetryingHttpRequesterFilter
now available under io.servicetalk.http.netty
package. The new filter offers support for handling lower level transport errors and retrying them (ie. what Auto-Retry was offering before) as well as allowing users to define their own retry rules per request/response basis.
RetryingHttpRequesterFilter
offers fine grain control over retry behavior, here are some highlights:
retryRetryableExceptions
Supports retry behavior forRetryableException
which are transport layer errors that occur inside ST and signal erroneous behavior before a request touches the “wire”. By default this is enabled and behaves the same way Auto-Retry was before.retryIdempotentRequests
Supports retry behavior for requests that are marked as idempotent when an I/O exception occurs.retryDelayedRetries
Supports retry behavior for errors that are type ofDelayedRetry
a marker interface that holds additional backoff time info, to be evaluated when the total back-off time is computed. One possible situation that this can be useful is if users want to translate aRetry-After
header in a response, and allow the retry-filter to wait for that amount of time (ie. retry-after period) before retrying.responseMapper
&retryResponses
Supports mapping any response to anHttpResponseException
giving the ability to users to retry particular responses according to their own criteria. First you map the response to an error withresponseMapper
then you define the retry behavior throughretryResponses
.
All above flavors offer fine control over the retry behavior of each retry criterion, e.g retry up-to 5 times retryable exceptions, and up-to 2 times delayed retries with max-delay of 2 seconds. On top of that, users can define a max-total
retry count, that can be used to exit the retry logic if the cumulative amount of retries (of all retry configurations) reaches that count.
The RetryingHttpRequesterFilter
is by default enabled and added as the last filter in the filter chain, similarly to how auto-retry behaved before, only retrying RetryableException
s, however if users define their own version of that and apply it in a particular placement in their filter chain, then this order/configuration takes precedence over the default behavior.
This work was ignited as an effort to minimize the places users have to define retry logic, and avoid situations where these placements conflict with each other resulting in retry logic that wasn’t expected.
Serialization
Interfaces from the io.servicetalk.serialization.api package have been deprecated (SerializationProvider
, ..). The deprecated interfaces have been replaced with new interfaces in io.servicetalk.serializer.api. The new APIs apply lessons learned from usage of deprecated APIs and here are some highlights:
- Composition between scalar serializers in streaming use cases. Streaming serializers provide reusable framing (Length Delimited VarInt/Fixed, gRPC) across different serialization technologies (Protobuf, thrift, ..).
- Encapsulation of serialization allows exposing streaming building blocks while hiding custom framing (gRPC SerializerDescriptor).
- Streaming APIs leverage Reactive Streams lifecycle and primitives instead of custom APIs and lifecycle.
- Support for JDK primitive types such as byte[] and String. See how these utilities are composed/leveraged in HttpSerializers.
Checkout the http serialization examples to see the new APIs in action. Javadocs on each deprecated type include @deprecated
notices referencing the replacement classes, and here is a summary of commonly used types:
- HttpSerializationProviders → HttpSerializers
- JacksonSerializationProvider → JacksonSerializerFactory
- ProtobufSerializationProvider → ProtobufSerializerFactory
Builders
General
- All builders (client & server, HTTP & gRPC) have been changed from abstract classes to interfaces to allows users wrap them to enhance/modify behavior. Method names didn’t change. HTTP users should not notice this change as soon as they recompile with 0.42, gRPC users may need to migrate their HTTP-specific configuration to
HttpInitializer
API (see #1867 and #1861). Resolving all deprecations highlighted building for 0.41.12 will make this transition smooth when upgrading to 0.42. - All one-way builder methods, like
HttpServerBuilder.disableDrainingRequestPayloadBody()
, have been changed to take aboolean
argument to allow users enable/disable a feature it controls. Migrate from all deprecated builder methods in 0.41.12 or see #1750, #1823, and #1825 for the full list of methods.
Server builders
- All
listen*
methods return a protocol-specific context now:Single<HttpServerContext>
for HTTP andSingle<GrpcServerContext>
for gRPC. Previously, these methods returnedSingle<ServerContext>
.
MultiAddressHttpClientBuilder & PartitionedHttpClientBuilder
- Both builders now use
SingleAddressInitializer
abstraction to give access to the underlyingSingleAddressHttpClientBuilder
(s)
MultiAddressHttpClientBuilder
maxRedirects(int)
→followRedirects(RedirectConfig)
- redirects are disable by default now, use
followRedirects(RedirectConfig)
to enable them
Filters API
- 0.41.12 simplified client-side filters API to remove
HttpExecutionStrategy
from the arguments, see #1956.
Users should update their filters to override one or more of the request
or reserveConnection
methods that does not take HttpExecutionStrategy
as an argument. If modifications for the HttpExecutionStrategy
are required, use HttpContextKeys#HTTP_EXECUTION_STRATEGY_KEY
. See changes for HostHeaderHttpRequesterFilter as an example of how to migrate a filter. After this migration is done with 0.41.12 version, 0.42 won’t cause any issues.
Note: All StreamingHttpClientFilter
implementations should use delegate.request(...)
instead of invoking super.request(delegate, ...)
. Invoking a super class implementation may lead to unexpected behavior change with new releases.
append
method have been removed from all filter factories:ConnectionFactoryFilter
,GrpcServiceFilterFactory
,MultiAddressHttpClientFilterFactory
,StreamingHttpClientFilterFactory
,StreamingHttpConnectionFilterFactory
,StreamingHttpServiceFilterFactory
because the resulting factories did not allow correct computation of the combined execution strategy. Consider using appropriateappend*
methods on the client/server builder intead.MultiAddressHttpClientFilterFactory
have been removed, migrate toMultiAddressHttpClientBuilder#SingleAddressInitializer
and useSingleAddressHttpClientBuilder#appendClientFilter(...)
.GrpcClientBuilder#MultiClientBuilder
andGrpcClientBuilder#buildMulti
have been removed, useGrpcClientFactory#newClient(GrpcClientCallFactory)
if necessary.
ServiceDiscoverer API
A new ServiceDiscovererEvent.Status
type was introduced to let SD use a non-binary state of the address. ServiceDiscovererEvent#isAvailable()
is replaced with ServiceDiscovererEvent#status()
.
DefaultDnsServiceDiscoverer
is using ServiceDiscovererEvent.Status.EXPIRED
by default.
ServiceDiscoveryRetryStrategy
and DefaultServiceDiscoveryRetryStrategy
have been deprecated in 0.41.12 and removed in 0.42 in favor of a standard BiIntFunction<Throwable, ? extends Completable>
API of RetryStrategies
.
LoadBalancer API
-
LoadBalancerFactory#newLoadBalancer
:- an extra
String
argument was added that describes a target resource for connections. It helps with debuggability. eventStream
publisher was changed fromPublisher<? extends ServiceDiscovererEvent>
toPublisher<? extends Collection<? extends ServiceDiscovererEvent>>
to align it withServiceDiscoverer
API.
- an extra
-
RoundRobinLoadBalancer.RoundRobinLoadBalancerFactory
become a top level class with the builder. -
RoundRobinLoadBalancer
changed its visibility frompublic
to pkg-private,RoundRobinLoadBalancerFactory
should be used instead. -
RoundRobinLoadBalancer.RoundRobinLoadBalancerFactory.Builder#eagerConnectionShutdown(boolean)
was removed becauseServiceDiscovererEvent.Status
can provide all necessary information. The same behavior can be achieved by configuringDefaultDnsServiceDiscovererBuilder#missingRecordStatus(ServiceDiscovererEvent.Status.UNAVAILABE)
.
If you have a custom implementation of the LoadBalancer
interface, consider supporting all new statuses from the ServiceDiscoverer
: AVAILABLE
, UNAVAILABLE
, EXPIRED
.
HTTP API
- Parent interface of StatelessTrailersTransformer have been changed from
TrailersTransformer<Object, Payload>
toTrailersTransformer<Void, Payload>
. BlockingStreamingHttpServerResponse
was converted from anabstract class
to aninterface
.HttpClients.*viaProxy(...)
methods have been removed in favor ofSingleAddressHttpClientBuilder#proxyAddress(...)
configuration option after using a regularHttpClients.forSingleAddress(...)
factory.
Exceptions
Removed exception types that were public but never thrown by ServiceTalk (see #1920):
ConnectionClosedException
InvalidRedirectException
MaxRequestLimitExceededException
MaxRequestLimitExceededRejectedSubscribeException
Some exception types were changed to use more appropriate parent type:
ConnectionRejectedException
extendsRuntimeException
→SocketException
;NoAvailableHostException
extendsRuntimeException
→IOException
;DuplicateAttributeException
extendsRuntimeException
→IllegalStateException
;TerminateRepeatException
extendsException
→RuntimeException
;ClosedServiceDiscovererException
extendsRuntimeException
→ClosedChannelException
;
Observability
TransportObserver - gives low level visibility into L4 network level
Some existing callbacks were improved to take extra arguments that help to increase visibility:
TransportObserver#onNewConnection()
→TransportObserver#onNewConnection(Object, Object)
- tells which local/remote address is used for a new connection. Previously, it was impossible to know what was the remote peer if a connect attempt fails.ReadObserver#itemRead()
→ReadObserver#itemRead(Object)
- tells which object have been read from the network.WriteObserver#itemReceived()
→WriteObserver#itemReceived(Object)
- tells which object have been received for a write operation.WriteObserver#itemWritten()
→WriteObserver#itemWritten(Object)
- tells which object have been serialized and written to the OS network buffer.
New callbacks that have to be implemented:
WriteObserver#itemFlushed()
- notifies when a previously written object have been flushed to the network.StreamObserver#streamIdAssigned(long)
- notifies when a steam of a multiplexed connection (HTTP/2) gets an assigned id number.ConnectionObserver#onTransportHandshakeComplete()
- notifies when a transport protocol completes a handshake (like TCP 3-way handshake).
Tracing
Due to a bug in our B3 header handling, we weren’t able to handle all possible sampling states as defined by the specification. More specifically the lack of presence of x-b3-sampled
, was being mishandled as if the carrier was suggesting no-sampling.
The behavior was address by changing the API to support Boolean
type sampling flag, restoring the possibility of 3-state option.
InMemorySpanContext#isSampled
boolean → Boolean
Additional API changes:
- Removed
InMemoryTraceState
,SpanContext
was enhanced to bridge API gap. - Trace identifiers were removed from the
Span
level, instead theSpanContext
houses them now.
Other
NettyIoExecutors#createIoExecutor(ThreadFactory)
now requiresio.servicetalk.transport.api.IoThreadFactory
.
Removed functionality
- gRPC filters have been removed. HTTP filters should be used to cover most use-cases. When an API-specific filter is required or when you need to filter deserialized proto objects extending/wrapping your
GrpcClient
orGrpcService
should provide the same level of control.
Upgrading to ServiceTalk 0.42
ServiceTalk 0.42 contains significant API and behavior updates as well as new API deprecations. Most applications will require some changes to use the 0.42 release. For applications developed using ServiceTalk 0.41 or earlier the best approach for updating an application to use the 0.42 release is to begin by updating the application to use the latest 0.41 release, currently 0.41.12. Once all deprecation warning have been resolved and tests are passing, only then begin upgrading to the 0.42 release.
Applications built with much older ServiceTalk releases should upgrade incrementally through the latest release of each minor version until arriving at ServiceTalk 0.42. Fully rebuilding applications with each intermediate ServiceTalk version will provide the most complete deprecation and upgrading advice. Fully rebuilding applications with each intermediate ServiceTalk release will provide the most complete deprecation and upgrading advice and ensure that generated gRPC code is remains compatible with the application usage.
Application developers should also pay careful attention to the API deprecations found in 0.42. Future 0.42.X releases, when they occur, will be compatible with this 0.42.0 release, but 0.43 and beyond versions of ServiceTalk will remove the currently deprecated APIs. Fortunately, it is currently expected that the ServiceTalk API will be more stable in future releases through the eventual ServiceTalk 1.0 release. Thank you for your understanding and cooperation on the way to 1.0!
New features
- 4ce1aa6 - New Serializer APIs, consolidation of ContentCodec, and gRPC MethodDescriptor (#1673)
- f40a200 - gRPC add
MethodDescriptor
Collection to services (#1764) - 5569e81 - Introduce
TimeSource
inExecutor
(#1972) - f5ad671 - Introduce
HttpServerContext
andGrpcServerContext
(#1990) - 583aa24 - Add weight factor to the load balanced addresses (#1988)
- d1d577e - Add
ExecutionStrategyInfluencer
(#1832) - 506cfd2 - Configurable offloading for async close (#1948)
- c15ff24 - Configurable TransportEvent offloading (#1957)
- 6af1f60 -
ConnectionAcceptor
ConnectionFactory
offloading control (#1921) - 9db9b7f - HTTP OpenTracing filters
Format<TextMap>
support (#1758) - 6beebe8 - API to support start/stop accepting connections (#1741)
- 6017f38 - Add
Publisher#multicast
operator, fix Publisher#groupBy backpressure (#1472) - c38ddff -
Completable#concat(Completable...)
(#1941) - 9f0a924 - Conditional
publishOn
&subscribeOn
operators (#1689) - b980aaa - Add support for nonOffloading HTTP Server Filters (#1710)
- d3cc787 - Support additional constant delay for retries (#1754)
Behavior changes
- 83530f2 - Multi-address client: throw
MalformedURLException
instead ofIllegalArgumentException
(#1955) - e9d69fa - Adjust parent types for exceptions (#1924)
- 8f50732 - Disable offloading for routes if server offloading disabled (#1842)
Bug fixes
- 8cf0d86 -
DefaultCompositeCloseable
StackOverflowException (#1942) - 72a0e64 - Avoid error from connection closure when signals should be queued (#1850)
- c4699d2 - Fix B3 sampling API to support missing values (#1640)
- 76c30bf - Correctly accept responses with
grpc-encoding: identity
(#1745)
Improvements
- 68ddd1d - HTTP/2 messages with empty body should not have empty trailers (#1883)
- e7927b7 -
ZipkinPublisher
remove unnecessary data (#1767) - a4951c9 - Http conditional offload (#1724)
API Improvements
- f3e611b - Convert
BlockingStreamingHttpServerResponse
to an interface (#1986) - 73cf04b -
StatelessTrailersTransformer
: Object → Void state (#1985) - 40ba1fa - Rename special execution strategies (#1987)
- f581029 -
publishOn/subscribeOn
takeio.servicetalk.concurrent.Executor
(#1983) - 17c9a1d - Rename
subscribeShareContext
toshareContextOnSubscribe
(#1975) - 7f456a8 - Use connection execution context in proxy connect (#1951)
- b3c356a - Converting
GrpcClientBuilder
to interface (#1908) - 9eb3bf2 - Converting
GrpcServerBuilder
to interface (#1903) - 1c61791 - Returns for some
AsyncContext
methods (#1839) (#1898) - 3c9bd5c - Untangling
GrpcClientBuilder
fromSingleAddressHttpClientBuilder
(#1867) - eedf988 - Converting
HttpServerBuilder
to an interface (#1820) - d77785d - Converting
HttpClientBuilder
s to interfaces (#1819) - 603b2dc - Conditional offload consistent exception handling (#1705)
- 1a2aa05 - Relax OpenTracing
HttpHeaders
formatter to allow custom containers (#1703) - 418e4a4 -
NettyIoExecutors
executors supportIoThread
- 84be6a3 - Simplify API hierarchy of HTTP and gRPC client builders (#1743)
Removed API
- 3ac1487 - Remove gRPC filters (#1893)
- 2725206 - Retry unification deprecations removal (#2019)
- d6c8ce3 - Clean up
TransportObserver
after #2012 (#2015) - a234235 - Clean up
Read/WriteObserver
after #2013 (#2014) - 6498a4a - Remove deprecated constructors from
HttpHeadersFactories
(#2002) - a2b2bbf - Remove deprecated
HttpClients
factories for proxy (#1980) - bf17e6a - Remove deprecated
AbstractRetryingFilterBuilder
build methods (#1981) - c953e16 - Remove default impl from
ConnectionObserver
(#1982) - d410975 - Remove
subscribeShareContext
method (#1984) - 689246c - Cleanup
LoadBalancer
APIs (#1976) - 8b578f7 - Removing deprecated
ServiceDiscovererEvent
methods (#1962) - 1e96f77 - Clean up deprecated requester/client/filter API (#1960)
- 8387995 - Cleanup default methods from
HttpMetaData
(#1961) - b2cb23a - Clean up
AsyncContext
API (#1959) - b095506 - Removing deprecated
ServiceDiscoveryRetryStrategy
(#1949) - d9947bb - Remove unused exception types (#1922)
- 15e6a75 - Removing the public deprecated methods from gRPC builders (#1899)
- bc9fbbe - Clean up deprecated API after changes for redirects in #1792 (#1862)
- 8a9488e - Removing default implementations from
HttpClientBuilder
(#1866) - 3f58ab7 - Removal of deprecated one-way builder methods (#1844)
- 91d678a - Remove remaining disable* methods in builder APIs (#1826)
- 74ac390 - Removed
GrpcClientBuilder#MultiClientBuilder
(#1809) - 7d5e191 - Remove
payloadBody(CloseableIterable<Buffer>)
methods (#1802) - c4f3bdc - Remove
ExecutionStrategy
offload*
methods (#1794) - 171a765 - Cleanup of
PartitionedHttpClientBuilder
(#1731) - e0dcd99 -
MultiAddressHttpClientBuilder
API cleanup (#1721) - 8706542 - Remove
publishAndSubscribeOn
(#1649) - decf81d - Remove
recoverWith
operators that were deprecated in #1435 (#1635) - bfaf539 - Remove
Verifiers
factory that was deprecated in #1392 (#1633) - 7058755 - Remove deprecated
CharSequences
methods (#1634) - c304d8c - Remove
append
methods that were deprecated in #1578 (#1631) - edd0fd2 - Remove
backlog(int)
server builder option that was deprecated in #1375 (#1636) - c108732 - Remove
disableHostnameVerification()
that was deprecated in #1561 (#1637) - 2d8530c - Remove
allowPrematureClosureBeforePayloadBody()
that was deprecated in #1475 (#1638) - a6170f2 - Remove deprecated
idleTimeout()
methods (#1602) - 6aaa59a - Remove deprecated compression implementation (#1537)
- 3e357a9 - Remove deprecated SecurityConfigurator and Builder.secure() APIs (#1474)
- 4abbb69 - Remove deprecated
enableWireLogging
andenableFrameLogging
overloads (#1420)
Build/Release/Github actions
- 98611f4 - Remove last jUnit4 dependencies, finish migration to jUnit5 (#1568, #1624, #1658, #1660, #1779, #1780)
Dependency upgrades
- 8d37891 - Update Jackson 2.10.5.1 → 2.13 (#1783, #1879)
- This release includes Netty to 4.1.72 which contains an important fix for CVE-2021-43797 and Log4J to 2.16.0 which contains fixes for CVE-2021-44228 and CVE-2021-45046.
Documentation
- 3f12fbf - Add
[Http|Grpc]LifecycleObserver
examples (#1857) - 5b9d7a9 - Improve deprecation docs on
TypeHolder
(#1782) - 6c9b8cc - Javadoc improvements for
HttpServerBuilder#append*
methods (#1729) - 8da1b25 - Conditional
publishOn
andsubscribeOn
javadoc clarification (#1713)
Thank you
Every idea, review, and bug-report counts and so we thought it is worth mentioning those who helped in this area. Please report an unintended omission.
@bondolo
@cancecen
@chemicL
@danfaer
@idelpivnitskiy
@Krupskis
@madrob
@mikhail-shibanov
@rnett
@Scottmitch
@sikevux
@sullis
@tkountis
@vglushak