Sending Email with spring in a new thread issue - java

One of the functionalities of app that I'm developing is that an email is sent every time user get's his invoice registered in our system. Sending an email from Java app easy especially if using Spring framework. I use JavaMailSenderImpl and SimpleMailMessage from Spring framework and it works okay.
But I need to send email in a new thread so that communication with SMTP server does not slow down the rest of apps processes. Problem is that when I call
MailSender.send()
method from a new thread, email message is not sent, as opposed when sending in a same thread.
I tried with spring's #Async annotation, spring Executor and plain old java.lang.Thread but it doesn't work.
Can email be send asynchronously in java with spring? Had anyone a similar issue with this?
I can post some code samples if needed.
Tnx

It should work.
You need to tell Spring that it should pay attention to your #Async Annotation by:
<task:annotation-driven />
And there are some limitations you need to pay respect to:
the annotated method must belong to a spring bean
the invocation of the annotated method must be executed from a different Spring Bean (if you are using standard Spring AOP).

1) Add task namespace into spring context. The following xsd is for Spring 3.0 release.
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
2) Declare the executor in your spring context file.
<!-- Executor for the methods marked wiht #async annotations -->
<task:executor id="asyncExecutor" pool-size="25" />
3) Configure this to Spring task
<!-- Configuration for the Runtime -->
<task:annotation-driven executor="asyncExecutor" />
These are all the configuration you need in the Spring context file.
The method you need to perform asynchronously annotate it with #Async annotaion.
Now, all the methods annotated with #async will be handled be spring task executor asynchronously.

One of the known issues of executing code in an asynchronous thread is that the exceptions thrown by that code are lost, unless you provide a specific handler to catch them. The effect you see (namely, the #Async method failing both to properly execute and to show a clue for that failure in the form of a log or stacktrace of some sort) is typically produced by such an exception, indeed thrown but swallowed by the asynchronous thread.
One of the many possible reasons why your #Async method works when synchronous is that you are doing some database operation from the method. It works when synchronous, because you are probably calling it from a #Transactional method of another #Service, so for that thread a Session or EntityManager is found; but it does not work when asynchronous, because in this case you are on a new thread, and if the #Async method is not #Transactional itself there is no Session or EntityManager that could perform the operation.
TL;DR Provide an exception handler to catch exceptions that would be swallowed by the asynchronous thread otherwise, or for the sake of debugging use a big try/catch for the body of the #Async method. You will probably see some exception popping up, then you will need to take the proper actions to avoid it.

You need to enable the feature in Spring:
#EnableAsync
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}

Related

Spring Integration #Scheduled not working due to #Poller

I have a Spring Boot / Spring Integration application running that makes use of #Poller in Spring Integration and also #Scheduled on another method in a mostly-unrelated class. The #Poller is for polling an FTP server for new files. However I've found that it seems like the #Poller is somehow interfering with my #Scheduled method.
The #Poller has maxMessagesPerPoll = -1 so that it will process as many files as it can get. However, when I first start my application, there are over 100 files on the FTP server, so it's going to process them all. What I have found is that, if these files are being processed, then the #Scheduler stops triggering at all.
For example, if I set my #Scheduled to have a fixedDelay = 1 to trigger every millisecond and then start my application, the #Scheduled method will trigger a few times, until the #Poller triggers and begins processing messages, at which point my #Scheduled method completely stops triggering. I assumed that simply there was some task queue that was being filled by the #Poller so I simply needed to wait for all of the messages to be processed, but even after the #Poller is completely done and has processed all of the files, the #Scheduled method still does not trigger at all.
My thoughts are that maybe there is some task queue that is being filled by the #Poller, which is breaking my #Scheduled method, but if so, I still don't see any way that I can use a separate task queue for the different methods, or any other possible options for customizing or fixing this issue.
Does anyone have any idea what might be happening to my #Scheduled method, and how can I fix this?
#Poller:
#Bean
#InboundChannelAdapter(channel = "ftpChannel", poller = #Poller(cron = "0/5 * * ? * *", maxMessagesPerPoll = "-1"))
public MessageSource<InputStream> myMessageSource() {
//Build my message source
return messageSource;
}
#Scheduled:
#Scheduled(fixedDelay = 6000)
public void myScheduledMethod(){
//Do Stuff
}
They do use the same bean name for their scheduler taskScheduler.
It should only be a problem if you have 10 or more pollers (the default scheduler bean configured by Spring Integration has a pool size of 10 by default). A common mistake is having many queue channels (which hold on to scheduler threads for a second at a time, by default).
If you only have one poller, and not a lot of queue channels, I can't explain why you would get thread starvation.
You can increase the pool size - see Configuring the Task Scheduler.
Or you can use a different scheduler in the ScheduledAnnotationBeanPostProcessor.
As already pointed out, the problem is linked to task schedulers having the same name, although it may occur even if there are fewer than 10 pollers. Spring Boot auto-configuration provides scheduler with default pool size of 1 and registration of this scheduler may happen before the registration of taskScheduler, provided by Spring Integration.
Configuring task scheduler via Spring Integration properties doesn't help as this bean doesn't get registered at all. But providing own instance of TaskScheduler with adjusted pool size, changing pool size of auto-configured scheduler via spring.task.scheduling.pool.size property or excluding TaskSchedulingAutoConfiguration should solve the issue.
In our case, the Poller was used by inbound-channel-adapter to access mail from the IMAP server - but when it polls for an email with large attachments, it blocks the thread used by #Scheduled as it only uses a single thread for scheduling the task.
So we set the Spring property spring.task.scheduling.pool.size=2 - which now allows the #Scheduled method to run in a different thread even if the poller gets blocked (in a different thread) when trying to fetch mail from IMAP server

How pass context in multithreading threading

We use multithreading and need the context of the calling thread in each sub-thread. We're using Spring 4.3.
For example:
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
CompletableFuture.supplyAsync(() -> {
...
try {
// take the security context from the caller
SecurityContextHolder.getContext().setAuthentication(authentication);
doOperations()
This approach works fine for the Security context. It's passed from the caller thread (rest endpoint) and passes it to each created completable future.
At a given Class in the call chain, I've following construct:
#Context
protected ProvisioningContext provisioningContext;
#Context
protected UriInfo uriInfo;
How do I pass all contexts correctly in the newly created thread?
Approaches like ThreadContext.getContext() are not working.
You can try to implement something similar to what I described here
Customize/Extend Spring's #Async support for shiro
That is:
Use Spring's #Async annotation to execute tasks in different threads
Implement a custom ThreadPoolTaskExecutor that associates the current context(s) with the to be executed task
Make spring use this task executor by implementing a AsyncConfigurer
If you want to use something like CompletableFuture.supplyAsync or local executor services, you will end up with a lot of duplicated code compared to approached outlined above - using a thread pool that is managed by spring.
Especially for something like the authentication context it is important to take care of removing the context from the thread as well. Otherwise the context might still be attached to the thread if it is recycled be the executor service to execute another task.

Using Spring4 AsyncRestTemplate in a method which uses an #Async annotation

I am using the Spring4 AsyncRestTemplate to make calls to an External REST API service.
The method below is from a Spring #Service class. The AsyncRestTemplate is autowired from a Spring #Bean.
In the method, I register callbacks on the ListenableFuture response from the REST API call.
I don't use the returned ListenableFuture except for unit tests. The callbacks will handle the actual actions I want to take based on request success or failure.
ExternalServiceImpl.class
public ListenableFuture<ResponseEntity<ResponseBody>> makeExternalCall(RequestBody requestBody) {
HttpEntity<RequestBody> request = new HttpEntity<>(RequestBody, getDefaultHeaders());
ListenableFuture<ResponseEntity<ResponseBody>> responseEntity = asyncRestTemplate.exchange(serviceUri.toUriString(), HttpMethod.POST, request, ResponseBody.class);
responseEntity.addCallback(
(onSuccess) -> System.out.println("Success"),
(onFailure) -> onFailure.printStackTrace()
);
return responseEntity;
}
I plan on using the #EnableAsync annotation and setting up a ThreadPoolTaskExecutor as well as adding an #async annotation to the method in a manner similar to the procedure described here: Spring Asynchronous Methods
Questions
Is this redundant? Is there an additional benefit to scaling when
making the method async even though I'm using an
AsyncRestTemplate?
Is there anything considered best practice that I'm missing in
implementing this pattern?
Is there anything to watch out for?
#Async doesn't actually do anything until you add the #EnableAsync annotation to your application. When that happens, any code calling your makeExternalCall method will immediately return, and spring will look for a TaskExecutor bean to run the whole method asynchronously (rather than just your asyncRestTemplate service being the only async part of your code currently).
More info on the spring website: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

How to modify a camel endpoint at runtime

The problem
I have a spring mvc application that uses apache camel. I am confused on the role that the RouteBuilder class plays and how it actually gets initialized. I know that the docs say that the configure() method is:
Called on initialization to build the routes using the fluent builder syntax.
but when does this initialization occur? Does it occur at application startup or some time later when the route is about to be used?
The purpose of this question is ultimately to ask how I can modify the route at runtime. I want to be able to build different routes as needed.
Examples
xml definitions:
<service name="myService" tier="3">
<requestType>my.package.RequestType</requestType>
<responseType>my.package.ResponseType</responseType>
<endpoint>
<httpEndpoint>
<url default="true" value="someUrl"/>
<timeout value="5000"/>
</httpEndpoint>
</endpoint>
</service>
Route Builder template:
public class myRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
// When does this method get executed?
}
}
Questions
When does configure() execute?
How can I dynamically set the endpoint url?
You are able to use toD to dynamically change the endpoint at runtime based on an expression. See the documentation
If you want to change more of the route or add a completely new route then look at the API on the CamelContext. This Stackoverflow question has an example of adding a completely new route.
The lifecycle of the Camel service is documented here : https://camel.apache.org/lifecycle.html
Camel uses a simple lifecycle interface called Service which has a single start() and stop() method.
Various classes implement Service such as CamelContext along with a number of Component and Endpoint classes.
When you use Camel you typically have to start the CamelContext which will start all the various components and endpoints and activate the routing rules until the context is stopped again.
It is when the context starts that the various components start. Not sure i understand the dynamic url part. If it is to indicate a dynamic endpoint (if the data is this , then queue1 else queue2) you should be able to use something like the DynamicRouter EIP which is as explained here (https://camel.apache.org/dynamic-router.html)
You have several options.
Inject them as spring properties.
Inject them from external properties source.
Inject them from some bean method.
Then you can put the property value in a header and later put the value in the .toD("$header.routeEndpoint"). This can take care of dynamic endpoints.
Off course to rebuild the entire route you need to play with the API.

#Async Spring gets recalled for every request of different sessions

I have a spring #Async annotated method in a bean, then in the controller I call that bean's method on a user request, and I do it this way so I can get a progress back from that bean, and it works fine for that.
But when I open it from another session the controller appears to restart the method and the progress is back again to the start point.
How to do this correctly, I have a progress count number as a field in the bean. and I increment it in the #Async method then get back via AJAX request to in a controller that retrieves it from the bean.
but its like the controller have only one bean injected to it. or there is only one controller for the whole app, whats is wrong here ?
EDIT
I tested in with opening two different browsers and running the task but it gets reloaded in both.
Apparently Spring Controllers are singletons per web app (and when you think about it they should be), so they are not thread safe if you have a component wired to it.
Meaning that suppose you have bean A wired to controller AC if two users send requests to an AC method that uses bean A at the same time, you'll have wrong values for both or you'll have bean reconstructing at each call, so if user1 starts the task and after a while before the task is finished user2 comes into play and wants to start it too, then user1' values will reset and so on.
To avoid this I found that you should make beans that are wired to controllers annotated with Session Scoped using annotations or xml.
in my case I used
#Scope("session")
You should never annotate the controller, as it won't work and if it does it will give weird behavior.
you should also (if using annotations like me) add scoped-proxy="targetClass" in your <context:component-scan /> element

Categories