Spring bean RequestScope with Webflux - spring-webflux

Is there a pattern to use #RequestScope with Webflux? We used the approach suggested here (https://www.baeldung.com/spring-bean-scopes) but it gives below error.
No scope registered for scope name request

Request scope works on ThreadLocal which is not supported by Webflux because part of work can be delegated between threads and you cannot assume that request will be handled by one thread.
In such a case, you should take a look at Reactor Context which allows you to connect data with the request scope.

Related

ThreadLocal in spring web flux

I am new to spring webflux. I am trying to implement the ThreadLocal using spring webflux.
I have a requirement where I need to pass the header from one microservice to another microservice in webclient.
I do not want to pass the header from on service to another service carrying it manually and assigning it in each request.
So thought of using ThreadLocal when I can set it and can access that in webclient call.
I am try to find a sample application where I can refer ThreadLocal with in spring webflux.
You should not use ThreadLocal in reactive environment. Webflux (which based on Reactor) is a non blocking framework. It reuses threads so the steps of one reactive pipeline can run in different threads and also multiple requests can use the same thread concurrently - until one waits, another operation will be picked and executed. Imagine if your request puts something into threadlocal and waits - for example - on a db select, another request can override this value and the next pipeline stage of the original request will see that new value belongs to another request. Threadlocal is good for request-per-thread model.
For webflux, you can use contexts. For example put the value into the pipeline in a WebFilter, then you can retrieve it in any point of the reactive pipeline:
chain.filter(exchange).contextWrite(<your data>)
In the pipeline (in map/flatmap...)
Mono.deferContextual(...)
Here is the link for documentation.
Alternatively you can lift ThreadLocal's value on every operation using Hooks, but this is not a nice and bulletproof solution.

Micronaut Reactive Using #Error with ReactorHttpClient

I have an API with 2 layers Controller and Service with Micronaut, Kotlin & Project Reactor. This application needs to handle requests in non-blocking manner.
I have a Post function makePayment method as below
fun makePayment(payment: Payment): Mono<PaymentDetails> in class PaymentController.
This calls a service class PaymentService which also has the same function as above.
This service internally uses io.micronaut.reactor.http.client.ReactorHttpClient to make the payment with Bank.
What is the right way to handle exception here?
Option1
reactorHttpClient.exchange().onErrorResume()
In onErrorResume I will map it to custom error code with suitable HTTP Status.No other specific Global Error handling is done.
Option2
Uses Controller Advise approach to have a Global Exception Handler with #Error(global = true) as mentioned below.
https://docs.micronaut.io/latest/guide/index.html#globalErrorHandling
I tried both approaches and both works.
I would like to understand what is the right approach considering Non-Blocking server and reactive streams approach.
Also does the Global Exception Handler with #Error(global = true) going to work like a Blocking or Non-Blocking way?

Sleuth traceId and spanId not logged in activeMQ Listener

I'm trying to configure a microservice with Sleuth and ActiveMQ.
When starting a request I can properly see appName, traceId and spanId in logs of producer, but after dequeuing the message in listener I find only appName, without traceId and spanId.
How can I get this fields filled?
Right now I'm working with spring.sleuth.messaging.jms.enabled=false to avoid this exception at startup:
Bean named 'connectionFactory' is expected to be of type 'org.apache.activemq.ActiveMQConnectionFactory' but was actually of type 'org.springframework.cloud.sleuth.instrument.messaging.LazyConnectionFactory'
My dependencies:
org.springframework.boot.spring-boot-starter-activemq 2.5.1
org.springframework.cloud.spring-cloud-sleuth 3.0.3
Thank you all!
My understanding is that the properties you're looking for are set on the JMS message when the message is sent and then retrieved from the message when it is consumed. Since you're setting spring.sleuth.messaging.jms.enabled=false you're disabling this functionality. See the documentation which states:
We instrument the JmsTemplate so that tracing headers get injected into the message. We also support #JmsListener annotated methods on the consumer side.
To block this feature, set spring.sleuth.messaging.jms.enabled to false.
You'll need to find an alternate solution for the connection factory problem if you want to use Sleuth with Spring JMS. If you're injecting org.apache.activemq.ActiveMQConnectionFactory somewhere then you should almost certainly be using javax.jms.ConnectionFactory instead. Using the concrete type is bad for portability and use-cases like this where wrapper implementations are used dynamically.

How to access to request body using WebFlux and Netty HttpClient

I need to calculate some kind of digest of the request body using the WebClient of Webflux and this digest must be set into a HTTP header. Using the good old Spring MVC ClientHttpRequestInterceptor is easy because the request body is provided as an array of bytes.
The ExchangeFilterFunction does not provide access to the request body.
The body is sent as JSon and Spring uses Jackson in order to serialize Java objects, so an option could be serialize my Object into Json and calculate the digest on it, but this strategy has two drawbacks:
my code would repeat what Spring will do when the request is actually sent
there's no guarantee that the acutal bytes sent by Spring as a request are equal to what I've passed to the digest function
I suppose that I should use some low level API of Netty, but I can't find any example.
I implemented the solution proposed by #rewolf and it worked, but I encountered an issue because of the multi-threading nature of WebFlux.
In fact, it's possible that the client request is saved into the thread-local map by one thread, but a different thread tries to get it, so a null value is returned.
For example, it happens if the request to be signed is created inside a Rest controller method which has a Mono as a request body parameter:
#PostMapping
public String execute(#RequestBody Mono<MyBody> body){
Mono<OtherBody> otherBody = body.map(this::transformBodyIntoOtherBody);
...
webClient.post()
.body(otherBody)
.exchange();
...
}
According to Reactor specs, the Reactor Context should be used instead of Thread Local.
I forked #rewolf project and implemented a solution based on Reactor Context: https://github.com/taxone/blog-hmac-auth-webclient
This is not currently easy to do with WebClient. But there are ways to do so by intercepting the body post-serialization. This can be done by registering a custom encoder that intercepts the data after encoding, and the passes it to a custom HttpConnector to inject it as a header.
This blog post explains one way to achieve it: https://andrew-flower.com/blog/Custom-HMAC-Auth-with-Spring-WebClient
Edit: Currently this blog post doesn't take into account concurrent requests. See the accepted answer by Claodio for the modified approach.

WebClient instrumentation in spring sleuth

I'm wondering whether sleuth has reactive WebClient instrumentation supported.
I did't find it from the document:
Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, rest template, scheduled actions, message channels, Zuul filters, and Feign client).
My case:
I may use WebClient in either a WebFilter or my rest resource to produce Mono.
And I want:
A sub span auto created as child of root span
trace info propagated via headers
If the instrumentation is not supported at the moment, Am I supposed to manually get the span from context and do it by myself like this:
OpenTracing instrumentation on reactive WebClient
Thanks
Leon
Even though this is an old question this would help others...
WebClient instrumentation will only work if new instance is created via Spring as a Bean. Check Spring Cloud Sleuth reference guide.
You have to register WebClient as a bean so that the tracing instrumentation gets applied. If you create a WebClient instance with a new keyword, the instrumentation does NOT work.
If you go to Sleuth's documentation for the Finchley release train, and you do find and you search for WebClient you'll find it - https://cloud.spring.io/spring-cloud-static/Finchley.RC2/single/spring-cloud.html#__literal_webclient_literal . In other words we do support it out of the box.
UPDATE:
New link - https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/integrations.html#sleuth-http-client-webclient-integration
let me paste the contents
3.2.2. WebClient
This feature is available for all tracer implementations.
We inject a ExchangeFilterFunction implementation that creates a span
and, through on-success and on-error callbacks, takes care of closing
client-side spans.
To block this feature, set spring.sleuth.web.client.enabled to false.
You have to register WebClient as a bean so that the tracing
instrumentation gets applied. If you create a WebClient instance with
a new keyword, the instrumentation does NOT work.