I am trying to convert the following Spring task xml configuration to a purely code/annotation based version:
<task:executor id="xyz.executor"
pool-size="${xyz.job.executor.pool.size:1-40}"
queue-capacity="${xyz.job.executor.queue.capacity:0}"
rejection-policy="CALLER_RUNS"/>
<task:scheduler id="xyz.scheduler" pool size="${xyz.job.scheduler.pool.size:4}" />
<task:annotation-driven executor="xyz.executor" scheduler="xyz.scheduler" />
<bean id='xyzProcessor' class="xyz.queueing.QueueProcessor" />
<task:scheduled-tasks scheduler="xyz.scheduler" >
<task:scheduled ref="partitioner" method="createPartitions" cron="${xyz.job.partitioner.interval:0 0 3 * * *}" />
</task:scheduled-tasks>
Per the Spring spec, 28.4.1 (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html), they say that to go from XML like this:
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>
to code configuration is as simply as enabling either #EnableScheduling and/or #EnableAsync.
However, I don't see anywhere I can actually instantiate the scheduler. The javadoc for #EnableScheduling (http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html) shows how I can get plug in my own created Executor, though I'm not exactly sure what class it should be (I still want to be able to control the pool size, queue capacity, and rejection policy). It also shows how I can schedule my createPartitions method using the configureTasks override. However, I would like to be able to name my scheduler (so I can identify its threads) and control its pool size.
So, I wish to know these things:
1) What class can I use to set the executor fields that the XML has?
2) Is there a way to create a scheduler instance that I can control the name and pool size of?
Check out the types AsyncConfigurer, AsyncConfigurerSupport, and SchedulingConfigurer. They are helper types you can use to enhance your #Configuration class with async/scheduling configurations.
Across all of them, and the javadoc of #EnabledAsync, you'll find all the setup methods you need to setup your async/scheduling #Configuration class.
The example given equates
#Configuration
#EnableAsync
public class AppConfig implements AsyncConfigurer {
#Bean
public MyAsyncBean asyncBean() {
return new MyAsyncBean();
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
with
<beans>
<task:annotation-driven executor="myExecutor" exception-handler="exceptionHandler"/>
<task:executor id="myExecutor" pool-size="7-42" queue-capacity="11"/>
<bean id="asyncBean" class="com.foo.MyAsyncBean"/>
<bean id="exceptionHandler" class="com.foo.MyAsyncUncaughtExceptionHandler"/>
</beans>
SchedulingConfigurer has a similar setup for task:scheduler.
If you want more fine-grained control you can additionally implement the SchedulingConfigurer and/or AsyncConfigurer interfaces.
As belows,
Please notice the pools also,
#Configuration
#EnableScheduling
public class CronConfig implements SchedulingConfigurer{
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
}
And for the Asyncs,
#Configuration
#EnableAsync
public class AsyncConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
Note that #EnableAsync and #EnableScheduling has to be there for this to work.
Related
I have several methods with the annotation #Scheduled. For each annotation or a group of them I want a different scheduler to be used. For example:
Group A has 3 methods with #Scheduled annotation which need to use Scheduler X.
Group B has 5 methods with #Scheduled annotation which need to use Scheduler Y.
From what I have read in Does spring #Scheduled annotated methods runs on different threads?, if the scheduler is not specified then only one of those methods will run at a time.
I know how this connection can be done using xml-based annotation. But is there a way that this can be done using Java-based annotation only?
It can be done using java config. But not using an annotation attributes.
You could have a look at the Spring API doc for some extended example.
For example:
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
}
#Bean(destroyMethod="shutdown")
public Executor taskScheduler() {
return Executors.newScheduledThreadPool(42);
}
}
#Scheduled group is not yet supported. See this open issue.
If you want use more than one scheduler you have to create and configure them programmatically. For example:
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
[...]
#Bean(destroyMethod="shutdown", name = "taskSchedulerA")
public Executor taskSchedulerA() {
return Executors.newScheduledThreadPool(42);
}
#Bean(destroyMethod="shutdown", name = "taskSchedulerB")
public Executor taskSchedulerA() {
return Executors.newScheduledThreadPool(42);
}
}
#Service
public class MyService {
#Autowired #Qualifier("taskSchedulerA")
private Executor taskSchedulerA;
#Autowired #Qualifier("taskSchedulerB")
private Executor taskSchedulerB;
#PostConstruct
public void schedule(){
Executors.newScheduledThreadPool(42).schedule(new Runnable() {
#Override
public void run() {
functionOfGroupA();
}
} , ..);
}
}
I need to send a email in async way while saving the data into DB.
My approach was like this.
//I have tried with service layer annotating.But not worked.
#EnableAsync
class MyService{
public String saveMethod(List listOfData){
mail.sendEmailQuote(listOfData);
mail.sendEmailWorkflowTaskAssignment(listOfData);
myDao.saveData(listOfData);
}
}
I need to perform following methods in #Async way. Where should I put #EnableAsync annotation. This is not a Schedule related thing. This is happen when user click save button. Application is used flex spring blazeDS. There is no controller written by my self.
I have used #Async annotation in my code for following 2 methods. Those are in class call Mail.
#Async
sendEmailQuote(listOfData){}
#Async
sendEmailWorkflowTaskAssignment(listOfData){}
Could you help me to find where should I put #EnableAsync ?
I refer this sample
EnableAsync is used for configuration and enable Spring's asynchronous method execution capability, it should not be put on your Service or Component class, it should be put on your Configuration class like:
#Configuration
#EnableAsync
public class AppConfig {
}
Or with more configuration of your AsyncExecutor like:
#Configuration
#EnableAsync
public class AppConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
}
Please refer to it's java doc for more details.
And for the tutorial you followed, EnableAsync is put above Application class, which extends AsyncConfigurerSupport with AsyncExecutor configuration:
#SpringBootApplication
#EnableAsync
public class Application extends AsyncConfigurerSupport {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("GithubLookup-");
executor.initialize();
return executor;
}
}
Just make sure that #Async methods aren't called by the same class. Self invocation for proxy won't work.
Spring framework has an interface AsyncConfigurer (and AsyncConfigurerSupport) for configuring everything necessary for having a thread pool executor and being able to run methods asynchronously (with #Async).
But usually, it's not a good practice to share the same thread pool among different functionalities, so usually I qualified them with a name, and I specify that name in Async annotation for it to use one specific thread pool.
Thing is, I would like to configure them through this convenient interface AsyncConfigurer and not loosing qualification, but I'm not able to.
Trying this:
#Configuration
#EnableAsync
public class PusherAsyncConfigurerSupport extends AsyncConfigurerSupport {
#Autowired
ExecutorConfig config;
#Override
#Qualifier(value = "executorOne")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize());
...
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
That thread pool is still not recognized when put in an Async annotation.
So, what is it needed for configuring several thread pools this way? Or isn't it the way for that at all?
mark with #Bean annotation
#Bean
#Qualifier(value = "executorOne")
public Executor getAsyncExecutor() {
//..
return executor;
}
Attempting to have Spring JUnit runner run test with RabbitTemplate and the listener injected with a Mockito stubbed service class. Trying to verify interaction with the Mock. With the examples I've seen I thought this would be possible. RabbitMQ is working. When logging into the dashboard, I can see the messages there. Am able to consume messages also with standalone console application.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/spring/servlet-context.xml", "classpath:/spring/root-context.xml", "classpath:rabbitlistener-context-test.xml"})
public class ReceiveOrderQueueListenerTest {
#Mock
private ReceiveOrderRepository mockRepos;
#Autowired
RabbitTemplate rabbitTemplate;
#Autowired
SimpleMessageListenerContainer listenerContainer;
#InjectMocks
#Autowired
ReceiveOrderQueueListener receiveOrderQueueListener;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testAbleToReceiveMessage() {
RequestForService rfs = new RequestForService();
rfs.setClaimNumber("a claim");
rabbitTemplate.convertAndSend("some.queue", rfs);
verify(mockRepos).save(new OrderRequest());
}
}
then the rabbit-listener config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd">
<rabbit:connection-factory id="rabbitConnectionFactory" host="XXXXXXXXX.com" username="test" password="test" />
<!-- <rabbit:connection-factory id="rabbitConnectionFactory" host="localhost" username="guest" password="guest" /> -->
<rabbit:admin connection-factory="rabbitConnectionFactory" auto-startup="true" />
<rabbit:template id="tutorialTemplate" connection-factory="rabbitConnectionFactory" exchange="TUTORIAL-EXCHANGE"/>
<rabbit:queue name="some.queue" id="some.queue"></rabbit:queue>
<bean id="receiveOrderListener" class="XXXXXXXXXX.connect.message.ReceiveOrderQueueListenerImpl"></bean>
<rabbit:topic-exchange id="myExchange" name="TUTORIAL-EXCHANGE">
<rabbit:bindings>
<rabbit:binding queue="some.queue" pattern="some.queue"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
<rabbit:listener-container connection-factory="rabbitConnectionFactory">
<!-- <rabbit:listener queues="some.queue" ref="receiveOrderListener" method="handleMessage"/> -->
<rabbit:listener queues="some.queue" ref="receiveOrderListener" />
</rabbit:listener-container>
</beans>
Tried injecting in the MessgeListenerAdaptor as well thinking the test needed that to wire the listener correct as well. With the adaptor injected in, I am able to verify the delegate gets injected in and with the stub.
Test fails on no zero interactions with mock. I can log into rabbitmq and the messages are there. The injected listener object is not consuming messages from the queue during the run of this test.
Almost forgot, the said listener. Tried default signature and tried the designate method.
public class ReceiveOrderQueueListenerImpl implements ReceiveOrderQueueListener {
#Autowired
ReceiveOrderRepository receiveOrderRepository;
#Override
public void handleMessage(RequestForService rfs) {
System.out.println("receive a message");
receiveOrderRepository.save(new OrderRequest());
}
public void onMessage(Message message) {
receiveOrderRepository.save(new OrderRequest());
}
}
Any suggestions would be helpful and I appreciate your help ahead of time.
I can't see any synchronization in your test. Messaging is asynchronous by nature (meaning that your test can finish before the message arrives).
Try using a Latch concept, which blocks until the message arrives or until the timeout expires.
First you need a test listener bean for your queue:
#Bean
#lombok.RequiredArgsContructor
#lombok.Setter
public class TestListener {
private final ReceiveOrderQueueListener realListener;
private CountDownLatch latch;
public void onMessage(Message message) {
realListener.onMessage(message);
latch.countDown();
}
}
Make sure to configure it to be used in place of your original listener in the test context.
Then in your test you can set the latch:
public class ReceiveOrderQueueListenerTest {
#Autowired
private TestListener testListener;
#Test
public void testAbleToReceiveMessage() {
RequestForService rfs = new RequestForService();
rfs.setClaimNumber("a claim");
// Set latch for 1 message.
CountDownLatch latch = new CountDownLatch(1);
testListener.setLatch(latch);
rabbitTemplate.convertAndSend("some.queue", rfs);
// Wait max 5 seconds, then do assertions.
latch.await(5, TimeUnit.SECONDS);
verify(mockRepos).save(new OrderRequest());
}
}
Note that there are better ways how to use latches (e.g. channel interceptors or LatchCountDownAndCallRealMethodAnswer with Mockito), but this is the basic idea. See Spring AMQP testing reference for more info.
I'm trying to convert XML configuration for using Spring's tasks framework into purely code configuration. I'm able to reproduce the functionality but whenever I shut down the war on the Tomcat server the task scheduler lives on, it hangs (it doesn't hang with XML configuration). I've debugged to inspect the instances of scheduler and executor but I'm not seeing a difference so I'm not sure what could be causing it to hang.
Here is the XML configuration that works:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<task:executor id="com.work.gwx.pix.executor"
pool-size="${pix.job.executor.pool.size:1-40}"
queue-capacity="${pix.job.executor.queue.capacity:0}"
rejection-policy="CALLER_RUNS"/>
<task:scheduler id="com.work.gwx.pix.scheduler" pool-size="${pix.job.scheduler.pool.size:4}" />
<task:annotation-driven executor="com.work.gwx.pix.executor" scheduler="com.work.gwx.pix.scheduler" />
<bean id='queueProcessor' class="com.work.gwx.queueing.QueueProcessor" />
</beans>
Here is the code configuration:
#EnableAsync
#EnableScheduling
#Configuration
public class TaskConfiguration implements AsyncConfigurer, SchedulingConfigurer {
#Value("${pix.job.executor.max.pool.size:1}")
private int executorMaxPoolSize;
#Value("${pix.job.executor.queue.capacity:0}")
private int executorQueueCapacity;
#Value("${pix.job.scheduler.pool.size:4}")
private int schedulerPoolSize;
#Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, new ThreadPoolTaskExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
#Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadFactory(new ThreadPoolTaskExecutor());
executor.initialize();
return executor;
}
#Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(pixTaskScheduler());
}
#Override
public Executor getAsyncExecutor() {
return pixExecutor();
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
When I use setExecuteExistingDelayedTasksAfterShutdownPolicy(false) in code configuration it does shut down but I'm worried that might have adverse effects as that is set to true when done via XML configuration. Also, I should note, the QueueProcessor class is doing the work I want and I don't mind if delayed executions get cancelled -- I just don't want currently executing threads to be abruptly cancelled.
This is the message I get when it hangs:
SEVERE: The web application [/pix-queue-processor] appears to have
started a thread named [ThreadPoolTaskExecutor-1] but has failed to
stop it. This is very likely to create a memory leak.
Any ideas on what might be causing the hanging? Or, would using that commented out method let me do what I want (won't kill a running task but will cancel delayed tasks)?
Your Java based configuration isn't really a representation of the the XML configuration. There are at least 2 things that are different.
Your TaskExecutor has another TaskExecutor wired as a ThreadFactory this isn't the case in XML and also starts another TaskExecutor.
Your TaskScheduler uses a new TaskExecutor whereas the xml configuration use the one configured.
The have your task finished on shutdown you can set the waitForTasksToCompleteOnShutdown property on the TaskExecutor to true then any pending tasks will be completed and no new tasks will be accepted.
Also the call to initialize shouldn't be needed as the afterPropertiesSet method will be called by Spring which in turn calls initialize.
The following 2 bean definitions are more in line with the XML configuration (and you now have a single TaskExecutor instead of 3 and it will first finish tasks before shutdown.
#Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, pixExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
#Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}