Receivers and Correlators are two optional components of a performance test scenario that enables us to receive response from a separate message channel. We can for instance send a request through a REST API and await for the response in the file system or in a database.
Receiver has three mandatory properties. These are the number of concurrent
threads that should be created to receive responses, the
correlator to be used to match responses to requests, and the
source from where to receive the responses. An instance of
Correlator is also passed to the
Receiver for it to be able to
register the response.
It is a crucial responsibility of the
Receiver to spawn the threads and
establish communication channels. A
Receiver must start the defined number
threads to receive messages. These threads are later stopped with
Thread.interrupt(). It is up to the receiver threads to react accordingly. The
receiver threads must be executed as daemon threads and can be terminated at the end of the
test execution if they do not react to the interruption.
During a performance test execution there is just a single instance of a
Receiver created. For the developers convenience there is
AbstractReceiver. For the most common situations where the
Receiver simply creates a thread pool, there is
AbstractAutoSpawnReceiver. A developer just needs to extends the
run() method then. On the other hand,
HttpReceiver is an example
Receiver where the underlying framework did not allow us to spawn the
threads ourself and manages the pool itself, thus is extends
All received messages are passed to a
Correlator which notifies the correct
Correlator interface defines two methods, first
for the outbound requests (
registerRequest()), and second for the inbound
registerResponse()). The Correlator then correlates requests with
their responses and notifies
SenderTask of receiving the appropriate response to
the original request. This is done based on a correlation ID that is
extracted from both request and response. Upon a successful match,
SenderTask.registerResponse(Serializable) is called.
For performance reasons, all interface methods should be implemented thread safe without locking and or synchronization. All implementations should make sure that they do not keep eating up the memory and clean their data structures regularly.
For the developers convenience, there is
AbstractCorrelator that takes care
about matching the messages together. All one needs to implement are methods to extract the
correlation ID from both the request
getRequestCorrelationId()) and the response
Please note the difference that a response can actually contain multiple
IDs. The method for processing responses also takes a
MultiMap instance with the message headers. This is because some protocols
allow the same message header to be present multiple times (e.g. HTTP).
Correlator does not necessarily need to have just a passive role. It can
even add the correlation ID in the request if there is none yet. See
GenerateHeaderCorrelator that can be used for many protocols.
It is possible that multiple requests will be aggregated in a single response. It is a task
Correlator implementation to report all the aggregated responses. It is also
possible that a single request will trigger multiple responses. Again, a specialized
Correlator implementation can handle this situation and wait for all the parts
to be received.