I have two services, A and B, communicating via Spring Remoting with AMQP. A exposes a REST API and populates the MDC (Mapped Diagnostic Context) with a UUID.randomUUID() (from within a Filter) on every request (and clears it when processing is finished). Now I'd like to pass this UUID to B in the request/reply cycle so that...
... when a consumer in B starts processing the request, its MDC is populated with the UUID.
... when the consumer in B finishes processing the request, its MDC is cleared.
I've extended SimpleMessageConverter so as to set an AMQP header containing the UUID, but I don't really seem to figure out how/where to populate and how/where to clear the MDC in B. Can anyone please shed some light?
Inject another custom message converter into the AmqpInvokerServiceExporter.
Set the MDC (from the header) in fromMessage(), clear it when the reply is mapped (in toMessage).
Related
I have a bean which is MessageHandler to handle an incoming message. The message handler is of type org.springframework.integration.aws.outbound.S3MessageHandler, which uploads the message to amazon s3. The issue is that, the operations of this message handler is performed in a different thread. How can I ensure that I can track the transaction id is propagated all the way to the thread performing this transaction?
DEBUG [app-name,,] 22540 --- [anager-worker-1]
Also attached to this message handler is a progress listener of type com.amazonaws.services.s3.transfer.internal.S3ProgressListener. The callbacks to this listener are performed within a different thread altogether. I need the trace ids in this listener too.
INFO [app-name,,] 22540 --- [callback-thread]
You may use MDC logging feature and log your trace id and span id.
The key problem that you have several threads for processing that leads to question how to correlate the logs between them.. so,
Put traceid+span+unique message id into MDC of thread that processing request
Put uniq message id into MDC of thread that MessageHelper uses
Modify your appenders to print traceid, span, unique message id into logs
Such fields could be well indexed by ELK (or any similar tool, even grep).
Then, by searching in logs by uniq message id you'll find all logs record + threads names and other details like traceid and spanid
Sleuth can do this for you, you need to check the docs how to use its API: https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/using.html#using-creating-and-ending-spans
As you can see there, you can create a Span and you can also create a Scope (in SpanInScope ). The Scope is responsible for the context propagation, e.g.: handling the MDC for you so you don't need to do anything with the MDC.
What you need to do though is properly using this API so the context is propagated. This is usually done by instrumenting the ExuecutorService/CompletionService and/or Runnable/Callable (whichever you use). Here's how to implement such a thing:
Get the current Span in the caller thread (tracer.currentSpan())
Use this span and create a Scope (and a new Span if you need) in the "other" thread (inside of the thread-pool)
You don't need to do this on your own, Sleuth has a TraceRunnable (this is doing exactly what I described above) and a TraceableExecutorService.
I am facing an issue in camel coding as:
1). We have two layers of code , first one is consumer and another is producer.
2). Consumer is calling producer as producer has many microservices.
3). During call Producer is generating the Unique ID for transaction tracking.
4). We can call the producer directly and it will generate the resultset.
5). During the Producer call we have to add the Unique Log transaction ID in header from POSTMAN.
Now the question is if want to hit the producer directly and do not want to pass the log transaction ID, Is there any way that
my producer router understands that LOGTRANSACTION is not present in header and it will generate a header named as "LOGTRANSACTION"
and add the unique value ?
and if we hit the Consumer then the LOGTRANSACTION ID propagate as it is to the producer layer.
Presuming the header you are talking about is a Camel message header; you may add a new Processor in front of your existing route to inspect the incoming Message with getHeader("LOGTRANSACTION");,. If this header is not present, your new processor can do a setHeader("LOGTRANSACTION", newHeader); to attach it synthetically(somehow!). Bear in mind that If you do exchange.getIn().getHeader() all the inbound headers and body will be preserved but calls to getOut() will clear original IN message. If you want further (better) answers, please consider posting relevant parts of your route(s) as well.
We have a distributed application following microservice Architecture. In one of our microservice we are following producer-consumer pattern.
The producer receives requests, persists it to database, pushes the request into a BlockingQueue and sends the response back to the client. The consumer running on a separate thread is listening to the blocking queue. The moment it gets the request object it performs specific operations on it.
The request received by the producer is persisted to the database asynchronously using CompleteableFutures.
The problem here is how to forward TraceId to the methods processing the requestObject inside consumer thread. Since the consumer thread might process these objects much later after the response is sent to the consumer.
Also how to forward the traceId across Asynchronous calls?
Thanks
That's an interesting question. I think that what you can do is to persist the request together with its headers. Then on the consumer side you can use the SpanExtractor interface in a similar way as we do here - https://github.com/spring-cloud/spring-cloud-sleuth/blob/v1.3.0.RELEASE/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java#L351 (Span parent = spanExtractor().joinTrace(new HttpServletRequestTextMap(request));). That means that from the HttpServletRequest we're extracting values to build a span. Then, once you've retrieved the Span, you can just use Tracer#continueSpan(Span) method before processing, and then Tracer#detach(Span) in the finally block. E.g.
Span parent = spanExtractor().joinTrace(new HttpServletRequestTextMap(request));
try {
tracer.continueSpan(parent);
// do whatever you need
} catch(Exception e) {
tracer.addTag("error", doSthWithTheExceptionMsg(e));
} finally {
tracer.detach(parent);
}
I have a workflow whose message payload (MasterObj) is being enriched several times. During the 2nd enrichment () an UnknownHostException was thrown by an outbound gateway. My error channel on the enricher is called but the message the error-channel receives is an exception, and the failed msg in that exception is no longer my MasterObj (original payload) but it is now the object gotten from request-payload-expression on the enricher.
The enricher calls an outbound-gateway and business-wise this is optional. I just want to continue my workflow with the payload that I've been enriching. The docs say that the error-channel on the enricher can be used to provide an alternate object (to what the enricher's request-channel would return) but even when I return an object from the enricher's error-channel, it still takes me to the workflow's overall error channel.
How do I trap errors from enricher's + outbound-gateways, and continue processing my workflow with the same payload I've been working on?
Is trying to maintain a single payload object for the entire workflow the right strategy? I need to be able to access it whenever I need.
I was thinking of using a bean scoped to the session where I store the payload but that seems to defeat the purpose of SI, no?
Thanks.
Well, if you worry about your MasterObj in the error-channel flow, don't use that request-payload-expression and let the original payload go to the enricher's sub-flow.
You always can use in that flow a simple <transformer expression="">.
On the other hand, you're right: it isn't good strategy to support single object through the flow. You carry messages via channel and it isn't good to be tied on each step. The Spring Integration purpose is to be able to switch from different MessageChannel types at any time with small effort for their producers and consumers. Also you can switch to the distributed mode when consumers and producers are on different machines.
If you still need to enrich the same object several times, consider to write some custom Java code. You can use a #MessagingGateway on the matter to still have a Spring Integration gain.
And right, scope is not good for integration flow, because you can simply switch there to a different channel type and lose a ThreadLocal context.
I am facing the following error while using spring websockets:
Use case: On our server side code we have a fucntionality to search values in data base..if the values are not present in database..it will hit a servlet and get the data..The second part i.e., hitting servlet and getting the data is asynchronous call.
So for one request there are multiple things we have to search for in data base..
Example: In request we got a some parameter channel: 1
This channel is mapped to multiple ids say 1 is mapped to 1,2,3,4,5
In websocket once the request comes to server i will extract the channel and get all the id's mapped and run a loop over id's as follows:
for(int i=0;i<ids.length;i++)
{
SomeObject databaseRespObj=callToDatabase(i); //SomeObject contains two fields value exists and string values
if(!databaseRespObj.valuesExists)
{
AsynchronouscallToServelt(i);
//once response received it will send message immediately using session
}
}
While execution of above server side code,some times only i am facing the below error.
java.lang.IllegalStateException: Blocking message pending 10000 for BLOCKING
at org.eclipse.jetty.websocket.common.WebSocketRemoteEndpoint.lockMsg(WebSocketRemoteEndpoint.java:130) ~[websocket-common-9.3.8.v20160314.jar:9.3.8.v20160314]
at org.eclipse.jetty.websocket.common.WebSocketRemoteEndpoint.sendString(WebSocketRemoteEndpoint.java:379) ~[websocket-common-9.3.8.v20160314.jar:9.3.8.v20160314]
at org.springframework.web.socket.adapter.jetty.JettyWebSocketSession.sendTextMessage(JettyWebSocketSession.java:188) ~[spring-websocket-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.socket.adapter.AbstractWebSocketSession.sendMessage(AbstractWebSocketSession.java:105) ~[spring-websocket-4.2.4.RELEASE.jar:4.2.4.RELEASE]
Sorry if the above framing of the question is not clear.Will spring support sending asynchronous messages like normal javax websocket does Session.getAsyncRemote().sendText(String text)
What is the configuration made in spring to send asynchronous messages using websocket session
From what I understand, you have multiple threads sending messages on the same RemoteEndpoint when the asynchronous technique kicks in.
Seems very similar to this :
WebSocket async send can result in blocked send once queue filled
I don't thing you necessarily have to use Futures or mechanisms described in the above post.
What I don't really get is : why doing asynchronous call to servlets ? Ofcourse several could send messages on the same RemoteEndPoint..
But can't you simply make synchronous calls to the relevant classes and keep the same request-response flow that you use when records are found in your database ? :)
UPDATE
Since you added in comments the fact that you need to focus on speed, and since it seems that your current solution is not applicable, let's maybe have a look at the problem from a different angle.
I'm not a websocket expert but as far as I understand what you try to achieve with the asynch servlet calls is not possible.
However, if you change the design/config of your project, this should be achievable.
Personally I use Websockets to be able to send a message to an arbitrary user that did not necessarily made a request - as long as he is connected, he must get the message.
To do this, I simply use the SimpMessagingTemplate class offered by Spring in their websocket support. To send a message to ANY USER THAT I WANT, I do this :
#Autowired
SimpMessagingTemplate smt;
(.......)
smt.convertAndSendToUser(recipient.getUsername(), "/queue/notify", payload);
So in your case, you could, in your loop :
make class instance method calls (instead of a servlet, no network transit, you cannot be faster ! Just a call to your biz-logic / service / whatever)
every time a method returns data, use the SimpMessagingTemplate like in the snippet here above :)
you can still do it asynchronously if you want ! :)
By doing this, you reduce latency (calling servlets adds alot), and have a reliable technique.
You can easily and quickly send thousands of messages to one user or to several users, at your own discretion, without stumbling upon the "10000 for BLOCKING" problem, which probably comes from more than 1 servlet "answering the same question" ;)
To obtain a SimpMessagingTemplate from Spring, you will need to use the <websocket:message-broker> tag or the equivalent non-xml-java-config.
I suggest to check this doc which has more info :
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html
and the following post I created on SO where I am using it (I've got another problem in the post, related to spring configuration and context hierarchies, but at least you have some template code to look at, the code is working) :
Spring Websocket : receiving nothing from SimpMessagingTemplate
Spring : how to expose SimpMessagingTemplate bean to root context ?