How to get sleuth http headers for reactor netty client request via breakpoint? - spring

Given a client request of the form
return webClient.get()
.uri(customersUrl + id)
.retrieve()
.bodyToMono(Customer.class)
.block();
I would like to have a scriptable breakpoint at some place in the outgoing request where I can obtain the http headers, including any span id headers added by sleuth (and before any SSL encryption takes place). Preferably this breakpoint should be somewhere on the same thread as the above request - if the breakpoint is on the async thread that actually does the socket write, there is a danger that the next breakpoint hit will be that initiated by another client request.
There is a real reason why I need to use breakpoints like this so I can't do anything that requires modifying the code.
I have found places on the async thread where the http headers are available - e.g. in reactor/netty/http/HttpOperations.then but I am struggling to find a similar place on the original client thread. I'm hoping this isn't all deferred via lambdas or something until the async thread consumes the subscription.

Related

JMeter & socket.io - I can see the message I want, but the socket plugin is not showing what I expect

Here is the socket message I see in the browser debugger console:
More illustrative, perhaps:
I call an API operation that triggers this message over a socket.
What I Tried
To preclude inaccuracies, I started 2 instances of JMeter.
REST API call.
Revised version of the GitHub JMeter example of sockets.io, in which I just call a WebSocket Sampler repeatedly on wss://events.dev.myserver.com:443/socket.io/?EIO=4&transport=websocket.
I kicked off (2).
While that was running, I kicked off (1).
Expected
Eventually, (1) should show me a sampler in the View Results Tree with the message in the screenshot ("42" - GAME_STARTED)
Actual
The only messages I see look like this:
This is really all I want to do: run the appropriate sampler, a sufficient time after making the API call, to get the message.
Update
We succeeded in finding the message using python-socketio:
sio.connect("https://events.dev.server.com", transports='websocket',
headers={'Sec-WebSocket-Extensions: permessage-deflate', 'Sec-Fetch-Dest: websocket',
'Sec-Fetch-Mode: websocket',
'Cookie: ABCSESSIONDEV=NTI3MzkwNWUtMTJmNS00Y2U0LTk1NGUtMjQ2Mzk5OTYxZWE0'})
And here is the output:
Received packet MESSAGE data 2["message","{\"locationId\":110,\"name\":\"GAME_STARTED\",\"payload\":{\"id\":146724,\"boxId\":2002,\"userId\":419,\"createdAt\":\"2022-03-02T14:35:31\",\"lastModifiedAt\":\"2022-03-02T14:35:36.752\",\"completedAt\":\"2022-03-02T14:35:36.621\",\"activationMethod\":\"TAG\",\"nfcTagId\":\"xxxxxx\",\"gameCount\":1,\"app\":false}}"]
I would like to use the websocket plugin to do this in JMeter now.
tried adding Cookie to WebSocket call - only sids, no messages.
tried adding Cookie to an HTTPS request (like the above code) - 400, bad request.
Take a look at other fields of the HTTP Request, in particular HTTP Headers, most probably your JMeter request is missing some essential information.
My expectation is that in order to "start the game" (whatever it means) you need to open the page in the browser, authorize somehow, follow the steps of the protocol upgrade mechanism, etc. to wit exactly mimic what real browser does, all the request sequence which is prior to starting the game.
You might need to correlate dynamic parameters, add HTTP Header Manager, add HTTP Cookie Manager, etc.

Spring boot Webclient's retrieve vs exchange

I have started using WebClient in my Spring boot project recently.
Can somebody throw some light on the differences/usages between exchange and retrieve method in WebClient.
I undertand that exchange returns Mono<ClientResponse> and retrieve returns ResponseSpec, I just want to know when/why I should use each one of them.
Much Thanks.
Adding to #JArgente's answer.
According to the official documentation of the retrieve() method:
Perform the HTTP request and retrieve the response body.
...
This method is a shortcut to using exchange() and decoding the response body through
ClientResponse.
and the exchange() method
Perform the HTTP request and return a ClientResponse with the response status and headers. You can then use methods of the response to consume the body:
The retrieve() method decodes the ClientResponse object and hands you the ready-made object for your use. It doesn't have a very nice api for handling exceptions.
However on the other hand the exchange() method hands you the ClientResponse object itself along with the response status and headers. With exchange method you get fine grained control over your response objects and a better way to handle the response object and the exceptions.
If you just want to consume some api go with retrieve().
If you want a better control over your response objects, headers and exceptions, go with exchange().
Update 1
Starting from Spring 5.3, the exchange() method is deprecated due to possible memory/connection leaks. exchangeToMono() or exchangeToFlux() can be used instead.
Thanks #rhubarb for the update.
According to spring Webclient api documentation the difference between the two is that exchange retrieve in addition to the body other http response information like headers and status, while retrieve only returns body information.
So If you only need the body information you should use retrieve, because it is a shortcut for exchange and then get the body, but if you need other information like http status you must use exchange.

How to design a spring boot application that can process 1k requests a second

I have a rest controller which accepts post requests and returns the statuses of whether the operations are successfull or not. It works fine for 100 requests per second as I have multiple operations underlying it which at the end send the response.
There could be hundreds of users trying to send the requests to the controller, thereby its all done using a completable future and http Async invoker. The problem happens when there are a 1000 requests per second and then the controller threads are exhausted as there are already multiple thread processing multiple requests and all are waiting for there future to be complete and then sending the response.
How can I make my rest controller be able to handle 1000 requests per Second without breaking.
there are already multiple thread processing multiple requests and all are waiting for there future to be complete and then sending the response.
You can actually make you controllers asynchronous by making them return a CompletableFuture. Just chain the calls on the CompletableFuture returned by your service to convert them into a an appropriate response instead of using get() or join():
#RequestMapping
public CompletableFuture<ResponseEntity<…>> processRequest() {
return myService.getStatusFuture()
.thenApply(status -> convertToResponseEntity(status));
}
Of course for this to work properly you should have a truly asynchronous service. If you are using #Async or submitting tasks with CompletableFuture.supplyAsync(), this will just move the problem from the HTTP threadpool to another threadpool.
It depends on the servlet server you are using. In the application.properties file, you can use the server.* properties to set the parameters you need.
In this link you can find these properties under the EMBEDDED SERVER CONFIGURATION section. If you are using the default tomcat embedded server, check out the server.tomcat.* properties. Especially the server.tomcat.accept-count, server.tomcat.max-connections and server.tomcat.max-threads properties.

Spring Integration HttpRequestExecutingMessageHandler issue on HEADERS

Checking the headers HttpRequestExecutingMessageHandler i notice a common header,
accept-encoding, gzip which throws an Exception on response during the convertion phase, i.e. the message could not be converted throwing an error on response. Which is my guess related to the undelaying HttpClient used.
Is there any reason to put this header on the RestTemplate by default? Removing the header with the header filter the Rest request ran normally.
Also i tried to use a RestTemplate - but the header remains there, so just the header filter worked.
But when testing internally (using the HTTP Rest to connect distinct Integration instances) things worked normally, i.e. the header message is handled normally(and i don't know the reason since the out. problem occurred with outbound RestServers.
The flow as example is bellow.
Regards,
**
IntegrationFlows.from("theRequestChannel")
.transform(Transformers.fromJson(MyClass.class))
.enrichHeaders(m -> m.header("app_id", "appid"))
.enrichHeaders(m -> m.header("app_key", "app_key"))
.headerFilter("accept-encoding")
.handle(myHandler())
.get();
**
Fully unclear what you are asking. There is no an accept-encoding auto header in Spring Integration. I may assume that you have an HTTP Inbound Channel Adapter and this header is sent by the outside client to you application.
If the REST Service you need to call really doesn't like that headers, that us really a good choice to filter such a header before performing a request. Such a header is not configured on the RestTemplate, since you don't exclude it from there, but filter before reaching that RestTemplate.
Another option you can consider is a DefaultHttpHeaderMapper with its setOutboundHeaderNames() to configure a set of header patterns to transfer from the message to HTTP request. Of course, excluding the mentioned accept-encoding.

Calling SendAsynchronousRequest from Bakcground Thread

I am switching from the old API initWithRequest to the new iOS 5 API sendAsynchronousRequest. For the old one, the doc says the thread that sends the async request should also be responsible for handling the http response. To follow this rule I have to use the main thread to send the async request. Now with the new API, can I send async http request from whatever thread I want?

Resources