Fuse 6 is no longer supported
As of February 2025, Red Hat Fuse 6 is no longer supported. If you are using Fuse 6, please upgrade to Red Hat build of Apache Camel.Questo contenuto non è disponibile nella lingua selezionata.
45.5. Asynchronous Response
45.5.1. Asynchronous Processing on the Server Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
Overview Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
The purpose of asynchronous processing of invocations on the server side is to enable more efficient use of threads and, ultimately, to avoid the scenario where client connection attempts are refused because all of the server's request threads are blocked. When an invocation is processed asynchronously, the request thread is freed up almost immediately.
Note
Note that even when asynchronous processing is enabled on the server side, a client will still remain blocked until it receives a response from the server. If you want to see asynchronous behaviour on the client side, you must implement client-side asynchronous processing. See Section 46.6, “Asynchronous Processing on the Client”.
Basic model for asynchronous processing Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
Figure 45.1, “Threading Model for Asynchronous Processing” shows an overview of the basic model for asynchronous processing on the server side.
Figure 45.1. Threading Model for Asynchronous Processing
In outline, a request is processed as follows in the asynchronous model:
- An asynchronous resource method is invoked within a request thread (and receives a reference to an
AsyncResponse
object, which will be needed later to send back the response). - The resource method encapsulates the suspended request in a
Runnable
object, which contains all of the information and processing logic required to process the request. - The resource method pushes the Runnable object onto the blocking queue of the executor thread pool.
- The resource method can now return, thus freeing up the request thread.
- When the
Runnable
object gets to the top of the queue, it is processed by one of the threads in the executor thread pool. The encapsulatedAsyncResponse
object is then used to send the response back to the client.
Thread pool implementation with Java executor Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
The
java.util.concurrent
API is a powerful API that enables you to create a complete thread pool implementation very easily. In the terminology of the Java concurrency API, a thread pool is called an executor. It requires only a single line of code to create a complete working thread pool, including the working threads and the blocking queue that feeds them.
For example, to create a complete working thread pool like the Executor Thread Pool shown in Figure 45.1, “Threading Model for Asynchronous Processing”, create a
java.util.concurrent.Executor
instance, as follows:
This constructor creates a new thread pool with five threads, fed by a single blocking queue with which can hold up to 10
Runnable
objects. To submit a task to the thread pool, call the executor.execute
method, passing in a reference to a Runnable
object (which encapsulates the asynchronous task).
Defining an asynchronous resource method Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
To define a resource method that is asynchronous, inject an argument of type
javax.ws.rs.container.AsyncResponse
using the @Suspended
annotation and make sure that the method returns void
. For example:
Note that the resource method must return
void
, because the injected AsyncResponse
object will be used to return the response at a later time.
AsyncResponse class Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
The
javax.ws.rs.container.AsyncResponse
class provides an a abstract handle on an incoming client connection. When an AsyncResponse
object is injected into a resource method, the underlying TCP client connection is initially in a suspended state. At a later time, when you are ready to return the response, you can re-activate the underlying TCP client connection and pass back the response, by calling resume
on the AsyncResponse
instance. Alternatively, if you need to abort the invocation, you could call cancel
on the AsyncResponse
instance.
Encapsulating a suspended request as a Runnable Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
In the asynchronous processing scenario shown in Figure 45.1, “Threading Model for Asynchronous Processing”, you push the suspended request onto a queue, from where it can be processed at a later time by a dedicated thread pool. In order for this approach to work, however, you need to have some way of encapsulating the suspended request in an object. The suspended request object needs to encapsulate the following things:
- Parameters from the incoming request (if any).
- The
AsyncResponse
object, which provides a handle on the incoming client connection and a way of sending back the response. - The logic of the invocation.
A convenient way to encapsulate these things is to define a
Runnable
class to represent the suspended request, where the Runnable.run()
method encapsulates the logic of the invocation. The most elegant way to do this is to implement the Runnable
as a local class, as shown in the following example.
Example of asynchronous processing Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
To implement the asynchronous processing scenario, the implementation of the resource method must pass a
Runnable
object (representing the suspended request) to the executor thread pool. In Java 7 and 8, you can exploit some novel syntax to define the Runnable
class as a local class, as shown in the following example:
Note how the resource method arguments,
id
and response
, are passed straight into the definition of the Runnable
local class. This special syntax enables you to use the resource method arguments directly in the Runnable.run()
method, without having to define corresponding fields in the local class.
Important
In order for this special syntax to work, the resource method parameters must be declared as
final
(which implies that they must not be changed in the method implementation).
45.5.2. Timeouts and Timeout Handlers Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
Overview Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
The asynchronous processing model also provides support for imposing timeouts on REST invocations. By default, a timeout results in a HTTP error response being sent back to the client. But you also have the option of registering a timeout handler callback, which enables you to customize the response to a timeout event.
Example of setting a timeout without a handler Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
To define a simple invocation timeout, without specifying a timeout handler, call the
setTimeout
method on the AsyncResponse
object, as shown in the following example:
Note that you can specify the timeout value using any time unit from the
java.util.concurrent.TimeUnit
class. The preceding example does not show the code for sending the request to the executor thread pool. If you just wanted to test the timeout behaviour, you could include just the call to async.SetTimeout
in the resource method body, and the timeout would be triggered on every invocation.
Tip
The
AsyncResponse.NO_TIMEOUT
value represents an infinite timeout.
Default timeout behaviour Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
By default, if the invocation timeout is triggered, the JAX-RS runtime raises a
ServiceUnavailableException
exception and sends back a HTTP error response with the status 503
.
TimeoutHandler interface Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
If you want to customize the timeout behaviour, you must define a timeout handler, by implementing the
TimeoutHandler
interface:
When you override the
handleTimeout
method in your implementation class, you can choose between the following approaches to dealing with the timeout:
- Cancel the response, by calling the
asyncResponse.cancel
method. - Send a response, by calling the
asyncResponse.resume
method with the response value. - Extend the waiting period, by calling the
asyncResponse.setTimeout
method. (For example, to wait for a further 10 seconds, you could callasyncResponse.setTimeout(10, TimeUnit.SECONDS)
).
Example of setting a timeout with a handler Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
To define an invocation timeout with a timeout handler, call both the
setTimeout
method and the setTimeoutHandler
method on the AsyncResponse
object, as shown in the following example:
Where this example registers an instance of the
CancelTimeoutHandlerImpl
timeout handler to handle the invocation timeout.
Using a timeout handler to cancel the response Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
The
CancelTimeoutHandlerImpl
timeout handler is defined as follows:
The effect of calling
cancel
on the AsyncResponse
object is to send a HTTP 503 (Service unavailable
) error response to the client. You can optionally specify an argument to the cancel
method (either an int
or a java.util.Date
value), which would be used to set a Retry-After:
HTTP header in the response message. Clients often ignore the Retry-After:
header, however.
Dealing with a cancelled response in the Runnable instance Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
If you have encapsulated a suspended request as a
Runnable
instance, which is queued for processing in an executor thread pool, you might find that the AsyncResponse
has been cancelled by the time the thread pool gets around to processing the request. For this reason, you ought to add some code to your Runnable
instance, which enables it to cope with a cancelled AsyncResponse
object. For example:
45.5.3. Handling Dropped Connections Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
Overview Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
It is possible to add a callback to deal with the case where the client connection is lost.
ConnectionCallback interface Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
To add a callback for dropped connections, you must implement the
javax.ws.rs.container.ConnectionCallback
interface, which is defined as follows:
Registering a connection callback Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
After implementing a connection callback, you must register it with the current
AsyncResponse
object, by calling one of the register
methods. For example, to register a connection callback of type, MyConnectionCallback
:
asyncResponse.register(new MyConnectionCallback());
asyncResponse.register(new MyConnectionCallback());
Typical scenario for connection callback Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
Typically, the main reason for implementing a connection callback would be to free up resources associated with the dropped client connection (where you could use the
AsyncResponse
instance as the key to identify the resources that need to be freed).
45.5.4. Registering Callbacks Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
Overview Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
You can optionally add a callback to an
AsyncResponse
instance, in order to be notified when the invocation has completed. There are two alternative points in the processing when this callback can be invoked, either:
- After the request processing is finished and the response has already been sent back to the client, or
- After the request processing is finished and an unmapped
Throwable
has been propagated to the hosting I/O container.
CompletionCallback interface Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
To add a completion callback, you must implement the
javax.ws.rs.container.CompletionCallback
interface, which is defined as follows:
Usually, the
throwable
argument is null
. However, if the request processing resulted in an unmapped exception, throwable
contains the unmapped exception instance.
Registering a completion callback Copia collegamentoCollegamento copiato negli appunti!
Copia collegamentoCollegamento copiato negli appunti!
After implementing a completion callback, you must register it with the current
AsyncResponse
object, by calling one of the register
methods. For example, to register a completion callback of type, MyCompletionCallback
:
asyncResponse.register(new MyCompletionCallback());
asyncResponse.register(new MyCompletionCallback());