Evolving to asynchronous
|This document elaborates how to disable offloading, which is considered an advanced feature.|
ServiceTalk provides ways for users start with a simpler blocking programming model and slowly evolve to a completely asynchronous programming model. Motivation and general principles can be found here. This document contains details how to disable offloading for an HTTP client/server.
For a client, there are two distinct ways of turning off offloading:
Disable offloading per request.
Disable offloading for the entire client.
For a client which is used for blocking as well as asynchronous programming models requests, (1) is the suggested mode of operation.
HTTP clients for all programming models recognize
allows to override offloading by passing its value in
In order to disable offloading for a specific request one has to use a specific
HttpExecutionStrategy that does not
do any offloading. Such a strategy is available out of the box in
and can be used as below:
// Processing of this request does not have any blocking code HttpRequest request = httpClient.newRequest(method, requestTarget); request.context().put(HTTP_EXECUTION_STRATEGY_KEY, HttpExecutionStrategies.noOffloadsStrategy()); HttpResponse response = httpClient.request(request);
For a request made using this strategy, ServiceTalk will not perform any offloading and all user calls may be invoked on the EventLoop.
|It is assumed that no blocking code exists during the entire processing of this request. If this assumption is violated then it will negatively impact the responsiveness of other work done on that EventLoop.|
If it is certain that no blocking requests will be made using a client without explicitly overriding the strategy, then one can disable offloading for the entire client using the following option on the client builder.
This strategy will be used for all requests that do not explicitly specify a strategy.
|Beware of inadvertently adding a request which uses blocking code to a client that has offloading disabled.|
ServiceTalk is designed in a layered fashion to enable extensibility. Therefore the core is unaware of a specific routing technology (e.g. JAX-RS) and assumes any routing is implemented inside the service provided to the server. This enables us to provide vastly different routing solutions without changing the core of ServiceTalk. However, it does mean that ServiceTalk only knows the programming model of the service that implements routing and not the programming model of the routes for each request. Since, ServiceTalk has to select an execution strategy before invoking the service (router) this means that an individual route can not entirely control all offloading done by the server. Hence, all routers in ServiceTalk have two execution strategies in play for any request processing:
Strategy for the server: All code that constitutes request processing in a server apart from the actual route.
Strategy for a route: Route implementation for a particular request.
Execution strategy for a server can be specified on the server builder just like the client. In order to disable offloading for the entire server, the following option can be used:
This strategy will be used for all requests processed by this server.
|Beware of inadvertently adding blocking code to a server that has offloading disabled.|
Each route added to any router may define an independent execution strategy which is used to invoke that route. Different routers may provide different ways of specifying that strategy, however, conceptually there are two ways to specify such a strategy:
A router may have the ability to infer an appropriate execution strategy for a route from the programming model the route uses, just like ServiceTalk infers execution strategy per programming model. This auto-inference is only used if no strategy is explicitly specified for that route.
A router may also provide a capability for a route to explicitly define an execution strategy that is used to invoke
that route. In presence of such an explicit strategy, auto-inference of the route strategy is disabled. In order to
disable offloads, one should use
In order to effectively evolve to different programming models, one should ensure that each route defines its own strategy either implicitly (when supported by the router) or explicitly (for overrides or lack of implicit strategy capabilities in the router). Depending on server strategy for a route is dangerous because:
Server strategy may change, adversely impacting the route. If the server strategy does change, and the router doesn’t auto-infer the correct default strategy, then the effective strategy at each route maybe impacted.
Increasing scope of server strategy (to also be the default strategy for all routes) makes it hard to understand how changing that strategy may impact all routes. Typically, server strategy should be chosen based on all code that is executed before executing the actual route for a request.
Making sure that all routes can independently specify their strategy makes it easier to reason about the impacts of changing these strategies. ServiceTalk provided routers provide ways to explicitly specify a route strategy, implicit inference capabilities may vary. Check out Jersey Router to see its capabilities for per route strategies.