SI 5+ supports WebFlux, which means we can now build a reactive messaging system. However, it also means that the design has be thought through, and usual methods of error handling don't work. In a reactive flow, a message is a Publisher(Flux), and it doesn't throw an exception, but emits an error notification. Thus, the error channel header set on the message is useless because SI doesn't know that the Flux resulted in an error.
Consider the following code:
.handle(WebFlux.outboundGateway(m -> m.getPayload().toString(), webClient)
.expectedResponseType(YelpRecord.class)
.httpMethod(GET)
.mappedRequestHeaders(ACCEPT)
.replyPayloadToFlux(true))
.handle((GenericHandler<Flux<YelpRecord>>) (flux, headers) ->
flux
.doOnError(t -> log.error(t.getMessage(), t))
.doAfterTerminate(() ->
log.info("Completed streaming from: {}.", headers.get(DOWNLOAD_URI_HEADER))
)
.onBackpressureBuffer(
yelpArtifactoryProperties.getOnBackpressureBufferSize(),
BufferOverflowStrategy.ERROR)
)
What is missing in the above code snippet is sending the exception to the error channel configured on the message from doOnError. How can we do that?
Does ((MessageChannel) header.getErrorChannel()).send(...) work for you there in the .doOnError()?
The point is that you are right and this Flux in the message payload is already out of control by the Framework and if you would like to deal with its errors, you have to do that yourself. That is already your code with a doOnError() therefore the Framework can't help you already with something automatic.
Related
In my current project we are using aws-lambda to make a rest call to external service and consume the response. Happy path works fine but when it comes to connection-timeout or socket-timeout it is not working as expected. Little more details below
When making a call to external system and if the read-timeout scenario happens (external system connection got established but did not receive any response from the system within 15 sec) the aws lambda keeps waiting for the response till lambda-timeout (25 sec) and returns error.
But I expect the rest-call code invoked within lamda to throw the SocketTimeOutException or related one which is not happening.
Same thing, when I tried using a sample java code (using apache's http-client implementation which is what I have used in lambda) it works perfectly fine and I am getting proper exception thrown.
Initially we tried with jersey implementation for making rest-call and thought this is having issue and changed to http-client implementation, but none of them thrown the exception as it does in sample java code.
Please let me know your suggestions or solutions if faced already.
Below is the code snippet that I use in both lambda as well as sample program for making the rest call. (this whole block is wrapped under try-catch)
HttpPost post = new HttpPost(URL);
RequestJSONObject request = new RequestJSONObject();
//setting required request payload
ObjectMapper mapper = new ObjectMapper();
String jsonStr = mapper.writeValueAsString(request);
post.setEntity(new StringEntity(jsonStr));
post.addHeader("content-type", "application/json");
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(1000)
.setSocketTimeout(3000).build();
CloseableHttpClient httpClient =
HttpClientBuilder.create().setDefaultRequestConfig(config).build();
CloseableHttpResponse response = httpClient.execute(post);
Thanks,
Ganesh Karthik C.
I'm using spring boot 2.2.4.RELEASE
I need to build a dynamic mail receiver because I can have several mail server where to fetch mails. The mail server must be configurable by other systems so my requirement is to be dynamically able in fetching messages.
I investigated and I liked the Spring Integration solution and its DSL (note: it's enough to me to simply download messages and their attachments, if any).
So I built this code:
String flowId = MAIL_IN_FLOW_ID_PREFIX+cpd.getIndirizzoMail();
if( flowContext.getRegistrationById(flowId) != null ) {
flowContext.remove(flowId);
}
ImapMailInboundChannelAdapterSpec adapterSpec = Mail.imapInboundAdapter(connectionUrl.toString())
.javaMailProperties(javaMailProperties)
.shouldDeleteMessages(false)
.shouldMarkMessagesAsRead(false)
.selector(selectFunction);
if( confMailIn.isRichiedeAutenticazione() ) {
adapterSpec = adapterSpec.javaMailAuthenticator(new CasellaPostaleAuthenticator(cpd.getUsername(), cpd.getPassword()));
}
IntegrationFlow flow = IntegrationFlows
.from(adapterSpec.get(), e -> e.poller(Pollers.fixedDelay(Duration.ofSeconds(pollingSeconds)).maxMessagesPerPoll(maxMailMessagePerPoll)))
.handle(message -> {
logger.info("Message headers "+message.getHeaders());
logger.info("Message payload "+message.getPayload());
})
.get();
flowContext.registration(flow).id(flowId).register();
I tried by using my gmail account. The code is able in connecting to GMAIL by imap but, when I try to simply log messages, I get this error:
A6 OK Success
2020-02-05 12:48:41,835 23412 [task-scheduler-1] DEBUG
o.s.i.mail.ImapMailReceiver - Received 10 messages
2020-02-05 12:48:41,836 23413 [task-scheduler-1] DEBUG oA7 STORE 1
+FLAGS (\Flagged) .s.i.mail.ImapMailReceiver - USER flags are not supported by this mail server. Flagging message with system flag
A7 NO STORE attempt on READ-ONLY folder (Failure)
A8 CLOSE
A8 OK Returned to authenticated state. (Success)
DEBUG IMAP: added an Authenticated connection -- size: 1
2020-02-05 12:48:42,198 23775 [task-scheduler-1] ERROR
o.s.i.handler.LoggingHandler -
org.springframework.messaging.MessagingException: failure occurred
while polling for mail; nested exception is
javax.mail.MessagingException: A7 NO STORE attempt on READ-ONLY folder
(Failure); nested exception is:
com.sun.mail.iap.CommandFailedException: A7 NO STORE attempt on
READ-ONLY folder (Failure) at
org.springframework.integration.mail.MailReceivingMessageSource.doReceive(MailReceivingMessageSource.java:74)
at
org.springframework.integration.endpoint.AbstractMessageSource.receive(AbstractMessageSource.java:167)
at
org.springframework.integration.endpoint.SourcePollingChannelAdapter.receiveMessage(SourcePollingChannelAdapter.java:250)
Now it seems that by default the FOLDER is opened in READ_ONLY way and this seems to cause an error.
I'm stucked here and I can't figure out how to solve the issue.
May anybody give me a tip?
Thank you
Angelo
adapterSpec.get()
Issuing a get() on the spec circumvents Spring's bean initialization logic which switches the folder to read/write.
Either make the adapter a #Bean or simply remove the .get() and Spring will perform the initialization.
.from(adapterSpec, e -> ...
I'm seeing this error and I'm not sure where it's coming from. I am using cast v3 sdk in Chrome, the call stack includes cast_sender.js onMessage function. I believe it is happening after the receiver issues a broadcastStatus media message.
Has anyone seen this error message in the web console: "The map has changed since the iterator was created"?
Happens to me in the following code:
session.addUpdateListener(function listener (isAlive) {
// This is what causes the error
session.removeUpdateListener(listener);
});
It only happens when I have session.removeUpdateListener(listener);
I guess it's unhappy that I removed the listener.
Maybe it is the same kind of thing for you?
We are on .NET WebAPI framework and we are using swagger on top of web api for annotations and out of the box UI experience. So far, it just has been working great. However, when I return an error from WebAPI(Http 400) as following code:
return BadRequest("Some error");
However, when I do that, it seems like Swagger is not able to parse the error properly. It basically, show response 0. Which is wrong for sure because when I go to Chrome DevTools, I see that my request had a response of HTTP 400 as I expected.
How can I configure Swagger so that it is able to show the errors correctly? Or should I be throwing my errors a little bit differently to be able to see it in swagger?
You can annotate your actions like this
[ProducesResponseType(typeof(ResponseObjectTypeHere), 200)]
[ProducesResponseType(typeof(ErrorResponseObjectTypeHere), 400)]
You can also add something like this in the xml documentation if you enable swagger to read and use xml documentation
/// <response code="200">Description</response>
/// <response code="400">Description of error</response>
I used those in the .net core web api project with swagger, should be the same for regular .net web api project as well.
You can simply send the exception details to the client by enabling one of ABP's configurations (SendAllExceptionsToClients) in ***.Web.Core Module, like this:
public override void PreInitialize()
{
if (_env.EnvironmentName.ToLower() == "development")
Configuration.Modules.AbpWebCommon().SendAllExceptionsToClients = true;
}
Then you get the exception details on the client. Recommended only during development.
Background
I have a java server that is making an RPC call to a go server. The java rpc client and go rpc server are instrumented with lightstep. Everything about the trace looks normal except for where in the lightstep UI, the go rpc server span is placed.
The java span has ts 1493929521325 which is right before the request is sent to the go server. The go rpc server has 2 timestamps: 1493929521326 is when it received the request and started the span, 1493929521336 is after it responded and finished the span.
Problem
I would expect the UI to have the go span horizontally to the immediate right of the java span. Instead, it is far to the right.
The only possible cause I can think of is an incompatibility between v0.10.1 which java code is using and v0.9.1 which go is using. Is this a possibility? Do you have any thoughts on a possible cause?
The go code is essentially:
import (
lightstep "github.com/lightstep/lightstep-tracer-go"
opentracing "github.com/opentracing/opentracing-go"
)
tracer := lightstep.NewTracer(lightstep.Options{
AccessToken: ls.AccessToken,
Collector: lightstep.Endpoint{ls.Host, ls.Port, true},
Tags: map[string]interface{}{lightstep.ComponentNameKey: component},
})
spanContext, err := tracer.Extract(opentracing.TextMap, opentracing.TextMapCarrier(req.GetLightstepData()))
span = tracer.StartSpan(
endpoint,
opentracing.ChildOf(spanContext))
}
// handle the request
span.Finish()
[Disclaimer: I work at LightStep]
Sorry you're having trouble getting Java and Go to play well together. I suspect this is caused by time-correction being enabled in Java but not being used in Go.
You can disable time correction in Java using the withClockSkewCorrection(boolean clockCorrection)
option to turn off clockCorrection when passing in options to the LightStep tracer
Here is the updated README and a link to the option code
If you contact us via the [Support] button in LightStep, we should be able to get you sorted out. Please send us a note so that we can confirm that this is solved for you.
We'll start monitoring SO more carefully so that we catch these things earlier.
Thanks and happy tracing!
Will