When using RocketMQ, I sending a message by async, sometimes throw ConcurrentModificationException - rocketmq

I'm just sending a string, I don't know why this is happening。
client-version: 4.5.2
server-version: 4.5.2
hope somebody can help me !
enter image description here
enter image description here
private void sendMission(String pushId) {
try {
Message message = new Message();
message.setTopic(missionTpoic);
message.setBody(pushId.getBytes("utf-8"));
log.info("sendMission to MQ begin , message : {}", message);
rocketMQService.getProducer().send(message, new SendCallback() {
#Override
public void onSuccess(SendResult sendResult) {
log.info( "======== onSuccess ========== {}", sendResult);
}
#Override
public void onException(Throwable e) {
log.error( "======== onException ==========", e);
}
}, 10000L);
log.info("sendMission to MQ end, message : {}", message);
} catch (Exception e) {
throw new BusinessRuntimeException(BaseExceptionCode.SYSTEM_ERROR.getAdminCode(), e, "Occur a error when push message into mq.");
}
log.info("sendMissionDone!!! pushId : {}", pushId);
}
The exception is as followed:
2021-03-26 16:06:13 {:} ERROR [AsyncSenderExecutor_1] c.p.b.p.c.SuperPushMissionExecutor:138 -- ======== onException ==========
java.util.ConcurrentModificationException: null
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445)
at java.util.HashMap$EntryIterator.next(HashMap.java:1479)
at java.util.HashMap$EntryIterator.next(HashMap.java:1477)
at org.apache.rocketmq.common.message.MessageDecoder.messageProperties2String(MessageDecoder.java:387)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendKernelImpl(DefaultMQProducerImpl.java:767)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:557)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.access$300(DefaultMQProducerImpl.java:90)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl$3.run(DefaultMQProducerImpl.java:491)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

I don't know does the question is solved.It look like "rocketMQService.getProducer()" start a threadPool and send same "Message" using multi thread,and the "message.properties" is base on HashMap,when using thread to access HashMap it will throw ConcurrentModificationException.
so the solution is check you code on "rocketMQService.getProducer()" and don't use multi thread send same "Message".

Related

Spring batch - issue with explicitly setting the job as failed

I am trying to set the status of job as failed in afterJob listener based on few conditions. But the job commits the changes and exits by marking job completed. Below is how I am setting the status. What could be wrong here?
jobExecution.addFailureException(e);
jobExecution.setExitStatus(new ExitStatus("FAILED", "Incorrect data"));
jobExecution.setStatus(BatchStatus.FAILED);
Version: Spring Boot 2.7.0
public void afterJob(JobExecution jobExecution) {
String message = "Completed job.";
try {
//get context and batch
ExecutionContext executionContext = jobExecution.getExecutionContext();
//processing done here
} catch (Exception coe) {
jobExecution.addFailureException(coe);
jobExecution.setExitStatus(new ExitStatus("FAILED", "Could not complete job"));
jobExecution.setStatus(BatchStatus.FAILED);
message = jobExecution.getExitStatus().getExitDescription();
} finally {
try {
//Database update here. When this fails, the Job is expected be marked FAILED, but its marked COMPLETED
throw new Exception("DB update failed"); //simulating exception
} catch (Exception e) {
System.out.println("Exception while saving final details to DB. This is printed");
jobExecution.addFailureException(e);
jobExecution.setExitStatus(new ExitStatus("FAILED", "Could not complete job"));
jobExecution.setStatus(BatchStatus.FAILED);
}
}
}

Aws xray segement executor not running in background

I have an api like this
#GetMapping("/async-test")
public String api2() throws InterruptedException {
log.info("Before async");
myService.myAsync();
log.info("after async");
return "nothing important";
}
And myService.myAsync implementation like this
#Async
public void myAsync() {
CompletableFuture.supplyAsync(() -> {
try {
log.info("before thread ....");
Thread.sleep(3000);
log.info("after thread ....");
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
log.info("before returning result ....");
return "Result of the asynchronous computation";
}, SegmentContextExecutors.newSegmentContextExecutor());
}
The issue here is that API waits for 3 seconds to reply when using SegmentContextExecutors.newSegmentContextExecutor(), but if I remove the segment executor, the function run in the background successfully, but for sure I lose the segment trace id for logging.
So what should be done to fix this ?
Tech stack
Spring boot v.2.7.2
Java 11
Aws x-ray v.2.11.2

Camel no error handler invoked on exception with multipleConsumer=true and POJO #Consume Annotation

I've been trying to figure out how route errors to my own error handler with the following, seemingly simple configuration, but Camel is swallowing the exception without routing it to any error handler I configure. I've run out of ideas. Any help would be much appreciated.
I've got a seda route that supports multiple consumers:
#Component
public class MessageGenerator {
public static final String ERROR_GENERATOR_CHANNEL = "seda:my-error-generator?multipleConsumers=true&concurrentConsumers=3";
private final FluentProducerTemplate producerTemplate;
public MessageGenerator(FluentProducerTemplate producerTemplate) {
this.producerTemplate = producerTemplate;
}
public void generateMessage() {
producerTemplate
.to(ERROR_GENERATOR_CHANNEL)
.withBody("Hello World")
.asyncSend();
}
}
I've got two separate POJO consumers:
#Configuration
public class MessageConsumer1 {
#Consume(ERROR_GENERATOR_CHANNEL)
void receiveMessage(String message) {
System.out.println("Received message 1: " + message);
throw new NullPointerException("Error generated");
}
}
#Configuration
public class MessageConsumer2 {
#Consume(ERROR_GENERATOR_CHANNEL)
void receiveMessage(String message) {
System.out.println("Received message 2: " + message);
}
}
When I run the following example, the NullPointerException gets swallowed by the underlying Camel MulticastProcessor as we can see in the logs:
Received message 2: Hello World
Received message 1: Hello World
2022-01-15 13:40:23.711 DEBUG 32945 --- [error-generator] o.a.camel.processor.MulticastProcessor : Message exchange has failed: Multicast processing failed for number 0 for exchange: Exchange[] Exception: java.lang.NullPointerException: Error generated
2022-01-15 13:40:23.711 DEBUG 32945 --- [error-generator] o.a.camel.processor.MulticastProcessor : Message exchange has failed: Multicast processing failed for number 0 for exchange: Exchange[] Exception: java.lang.NullPointerException: Error generated
The exception only gets logged as debug and never gets propagated to any error handler I set up.
Any thoughts on how I could receive the error in my own error handler rather than Camel swallowing the exception as a debug statement?
Note1: I've attempted many variations on both default error handling and default dead letter handling to no avail. I could just be doing it wrong...
Note2: that I'm using Spring[Boot] here too, hence the #Configuration annotation.
Note1: I've attempted many variations on both default error handling and default dead letter handling to no avail. I could just be doing it wrong...
Haven't used #Consume annotations but generally if you want Camel route not to handle any errors you can use .errorHandler(noErrorHandler()). This can be used to pass the error back to parent route or all the way to the code calling ProducerTemplate.sendBody.
Example:
public class ExampleTest extends CamelTestSupport {
#Test
public void noErrorHandlerTest() {
try {
template.sendBody("direct:noErrorHandler", null);
fail();
} catch (Exception e) {
System.out.println("Caught Exception: " + e.getMessage());
}
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder(){
#Override
public void configure() throws Exception {
from("direct:noErrorHandler")
.errorHandler(noErrorHandler())
.log("Throwing error")
.throwException(Exception.class, "Test Exception");
}
};
}
}

Issue with a Spring #Async method not catching/rethrowing an exception

I am facing an issue since I enabled turned a synchronous method into an asynchronous one: if an exception is thrown from within the body of the method, I can no longer rethrow it.
Let me first show the code:
My async/task executor configuration:
#Configuration
#EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(25);
taskExecutor.initialize();
return taskExecutor;
}
}
My asynchronous method:
#Async
#Override
public void sendPasswordResetInfo(String email) {
Assert.hasText(email);
Member member = memberRepository.findByEmail(email);
try {
mailerService.doMailPasswordResetInfo(member);//EXCEPTION THROWN HERE
} catch (MessagingException | MailSendException e) {
log.error("MessagingException | MailSendException", e);
// TODO: not thrown since #Async is used
throw new MailerException("MessagingException | MailSendException");//NOT CALLED
}
}
All I see in the console when an exception is raised by mailerService.doMailPasswordResetInfo is the following stacktrace:
2014-06-20 18:46:29,249 [ThreadPoolTaskExecutor-1] ERROR com.bignibou.service.preference.PreferenceServiceImpl - MessagingException | MailSendException
org.springframework.mail.MailSendException: Failed messages: javax.mail.SendFailedException: Invalid Addresses;
nested exception is:
com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418]
; message exception details (1) are:
Failed message 1:
javax.mail.SendFailedException: Invalid Addresses;
nested exception is:
com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418]
at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1294)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:635)
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:424)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:346)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:341)
at com.bignibou.service.mailer.MailerServiceImpl.doMailPasswordResetInfo(MailerServiceImpl.java:82)
at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo_aroundBody10(PreferenceServiceImpl.java:112)
at com.bignibou.service.preference.PreferenceServiceImpl$AjcClosure11.run(PreferenceServiceImpl.java:1)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96cproceed(AbstractTransactionAspect.aj:59)
at org.springframework.transaction.aspectj.AbstractTransactionAspect$AbstractTransactionAspect$1.proceedWithInvocation(AbstractTransactionAspect.aj:65)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
at org.springframework.transaction.aspectj.AbstractTransactionAspect.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(AbstractTransactionAspect.aj:63)
at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo_aroundBody12(PreferenceServiceImpl.java:108)
at com.bignibou.service.preference.PreferenceServiceImpl$AjcClosure13.run(PreferenceServiceImpl.java:1)
at org.springframework.scheduling.aspectj.AbstractAsyncExecutionAspect.ajc$around$org_springframework_scheduling_aspectj_AbstractAsyncExecutionAspect$1$6c004c3eproceed(AbstractAsyncExecutionAspect.aj:58)
at org.springframework.scheduling.aspectj.AbstractAsyncExecutionAspect.ajc$around$org_springframework_scheduling_aspectj_AbstractAsyncExecutionAspect$1$6c004c3e(AbstractAsyncExecutionAspect.aj:62)
at com.bignibou.service.preference.PreferenceServiceImpl.sendPasswordResetInfo(PreferenceServiceImpl.java:108)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:97)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.sun.mail.smtp.SMTPAddressFailedException: 550 5.1.1 Adresse d au moins un destinataire invalide. Invalid recipient. OFR204_418 [418]
at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1145)
... 28 more
FYI, MailerException is a custom exception I used in the app. What really strikes me is that this MailerException exception does not appear to be caught nor rethrown...
Can anyone please help?
edit 1: I have modified my async service method as follows:
#Async
#Override
public Future<Void> sendPasswordResetInfo(String email) {
Assert.hasText(email);
Member member = memberRepository.findByEmail(email);
try {
mailerService.doMailPasswordResetInfo(member);
return new AsyncResult<Void>(null);
} catch (MessagingException | MailSendException e) {
log.error("MessagingException | MailSendException", e);
//HERE: HOW DO I SEND THE MailerException USING THE FUTURE??
throw new MailerException("MessagingException | MailSendException");
}
}
However, I am not sure how to send the MailerException to the web layer using the AsyncResult from within the catch block above...
Your logs show
2014-06-20 18:46:29,249 [ThreadPoolTaskExecutor-1] ERROR com.bignibou.service.preference.PreferenceServiceImpl - MessagingException | MailSendException
which is logged by
log.error("MessagingException | MailSendException", e);
the Exception that is then thrown
throw new MailerException("MessagingException | MailSendException");//NOT CALLED
is caught by the Thread executed by the underlying ThreadPoolTaskExecutor. This code is run asynchronously so the exception is thrown in a different thread than the thread that invokes the method.
someCode();
yourProxy.sendPasswordResetInfo(someValue()); // exception thrown in other thread
moreCode();
If you make your method return a Future as shown here you'll be able to invoke get() on it and that will rethrow any exception that was thrown inside the #Async method, wrapped in an ExecutionException.
By following this link http://www.baeldung.com/spring-async, you should create:
CustomAsyncExceptionHandler that implements AsyncUncaughtExceptionHandler
#Slf4j
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
#Override
public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
log.error("**********************************************");
log.error("Exception message - " + throwable.getMessage());
log.error("Method name - " + method.getName());
for (Object param : obj) {
log.error("Parameter value - " + param);
}
log.error("**********************************************");
}
}
SpringAsyncConfig that implements AsyncConfigurer
#Configuration
#EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
return new ThreadPoolTaskExecutor();
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
The solution i had was fixed by creating a configuration class that extends AsyncConfigurerSupport, since the above solutions did not work in my implementation. In this configuration class, i had to define SimpleAsyncTaskExecutor and an async exception handler. Inside the handler, i checked the throwable instance and based on its value, i implemented the needed behavior:
if ( throwable instanceOf CustomException) {
// TODO add code
} else {
// TODO
}
Reference: Effective advice on spring async exception handler

how to populate cvc-complex-type error information in mule

I have mule message filters to validate SOAP Request against schema,
my question is:
how to log error details of 'which element is have parse exception (cvc-complex-type). because catch block is always trowing exception details: "Message has been rejected by filter". how can i show exact exception?. so that user will enter correct data on request.
write a customfilterclass as a child of SchemaValidationfilter.
override accept method and throw soap fault.
public class CustomSchemaValidationFilter extends SchemaValidationFilter {
#Override
public boolean accept(MuleMessage muleMessage) {
return validateBody(muleMessage);
}
public boolean validateBody(MuleMessage message) throws Fault {
Source source = null;
try {
source = loadSource(message);
} catch (Exception e) {
throw getFaultObj(e);
}
try {
createValidator().validate(source);
} catch (SAXException e) {
throw getFaultObj(e);
} catch (IOException e) {
throw getFaultObj(e);
}
return true;
}
private Fault getFaultObj(Exception e) {
return new SoapFault(e.getMessage(), e, new QName(
DEFAULT_SCHEMA_LANGUAGE));
}
}
//and add in mule flow following tags to validate filter.
<custom-filter class="org.mule.module.xml.filters.CustomSchemaValidationFilter">
<spring:property name="schemaLocations" value="${approvalHistorySchemaLocation}" />
</custom-filter>**

Resources