I am using Spring 4. I use this for execute a task periodically for web sockets:
private TaskScheduler scheduler = new ConcurrentTaskScheduler();
In my class:
#Configuration
#EnableWebSocketMessageBroker
#EnableScheduling
#Component
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Autowired
private SimpMessagingTemplate template;
private TaskScheduler scheduler = new ConcurrentTaskScheduler();
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/simplemessages").withSockJS();
}
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic/", "/queue/");
config.setApplicationDestinationPrefixes("/app");
}
#PostConstruct
private void broadcastTimePeriodically() {
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
String statStr = "Server Response" + new Date();
System.out.println("thread schedular run time :" + Hello.printTime());
try {
template.convertAndSend("/topic/simplemessagesresponse", statStr);
} catch (MessagingException e) {
System.err.println("!!!!!! websocket timer error :>" + e.toString());
}
}
}, 4000));
}
#PreDestroy
private void destroyServices() {
scheduler = null; // how to destroy ?
}
public void configureClientInboundChannel(ChannelRegistration registration) {
}
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(4).maxPoolSize(10);
}
public boolean configureMessageConverters(List < MessageConverter > arg0) {
// TODO Auto-generated method stub
return true;
}
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration arg0) {
}
}
I want to know to things:
I found that the scheduler is running twice within 4000 milliseconds. How is it happening and how can I stop it?
I run this application in tomcat. As you can see, the method destroyServices() needs to destroy the schedular. Here the problem is, even the tomcat is restarted again, previously running thread is still running. So when the tomcat is going to down, that thread also should be terminated. I need to know How I can destroy it on tomcat is going to down or any system crash?
The following code snippet is from documentation of #EnableScheduling:
#Configuration
#EnableScheduling
public class AppConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
}
I think you should get the bean named taskExecutor (in this case) and call shutdown (in fact depending on your configuration) method of it.
Related
Probably something simple, but I can't figure it out on my own. I have some sample of Spring Boot WebSockets implementation and wanted to display total active sessions. So I created #Scheduled activeSessions task, which should display actual count, but it's always 0. When afterConnectionEstablished is called I get expected sessions size. Whats the catch?
#Configuration
public class Monitoring extends TextWebSocketHandler {
private List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message)
throws Exception {
String clientMessage = message.getPayload();
System.out.println(clientMessage);
sessions.forEach(s -> {
try {
s.sendMessage(new TextMessage("Hello! You session id is: " + s.getId()));
activeSessions();
} catch (IOException e) {
e.printStackTrace();
}
});
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//the messages will be broadcasted to all users.
System.out.println("Adding new session.");
sessions.add(session);
System.out.println("Current session count: " + sessions.size());
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
}
#Scheduled(fixedRate = 2000)
public void activeSessions() {
System.out.println("Total sessions: " + sessions.size());
}
}
Configuration part:
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(#NotNull WebSocketHandlerRegistry registry) {
registry.addHandler(new Monitoring(), "/socket");
}
}
Due conflict described, custom scheduler:
#Configuration
#EnableScheduling
public class SchedulingConfig {
// https://stackoverflow.com/questions/49343692/websocketconfigurer-and-scheduled-are-not-work-well-in-an-application
#Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
taskScheduler.initialize();
return taskScheduler;
}
}
You currently have 2 separate instances of the Monitoring class. One created by yourself, doing the request handling (which isn't a Spring managed bean!) and another one detected by Spring due to the #Configuration (shouldn't that be an #Component?).
Remove the #Configuration and replace it with an #Bean method, such that your WebSocketConfig looks like the following
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(#NotNull WebSocketHandlerRegistry registry) {
registry.addHandler(monitoring(), "/socket");
}
#Bean
public Monitoring monitoring() {
return new Monitoring();
}
}
You now have a single instance of the bean, managed by Spring.
I am following the example from here to run tasks in parallel using #EnableScheduling - from this tutorial
Here is my code -
#EnableScheduling
#Configuration
public class MyJobScheduler implements SchedulingConfigurer {
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(5);
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean
#Scope("prototype")
public MyJobExecutor createMyJobExecutor() {
return new MyJobExecutor();
}
#PostConstruct
public void registerServices() {
for (int i = 0; i < 5; i++) {
createMyJobExecutor();
}
}
}
public class MyJobExecutor {
private static final Logger logger =
LoggerFactory.getLogger(MyJobExecutor.class);
#Autowired
MyService myService;
#Scheduled(fixedDelayString = "10000", initialDelayString = "30000")
public void runJob() {
try {
logger.info("MyJobExecutor executing...");
myService.myJobTask();
} catch (Exception e) {
logger.error(MyJobExecutor failed.", e);
}
}
}
#EnableScheduling
#Configuration
public class MyJobScheduler2 implements SchedulingConfigurer {
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(2);
}
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean
#Scope("prototype")
public MyJobExecutor2 createMyJobExecutor() {
return new MyJobExecutor2();
}
#PostConstruct
public void registerServices() {
for (int i = 0; i < 2; i++) {
createMyJobExecutor();
}
}
}
public class MyJobExecutor2 {
private static final Logger logger =
LoggerFactory.getLogger(MyJobExecutor2.class);
#Autowired
MyService2 myService;
#Scheduled(fixedDelayString = "10000", initialDelayString = "30000")
public void runJob() {
try {
logger.info("MyJobExecutor2 executing...");
myService.myJobTask();
} catch (Exception e) {
logger.error(MyJobExecutor2 failed.", e);
}
}
}
When I have just one scheduler configured, MyJobScheduler, I get the expected number of jobs running in parallel. However, I need 2 scheduled jobs. When I add MyJobScheduler2, here are the logs...
21:03:25.291 [pool-2-thread-1] INFO c.t.m.e.s.e.p.p.MyJobExecutor2 - MyJobExecutor2 executing...
21:03:25.459 [pool-2-thread-2] INFO c.t.m.e.s.e.p.p.MyJobExecutor2 - MyJobExecutor2 executing...
21:03:25.537 [pool-2-thread-1] INFO c.t.m.e.s.e.p.p.MyJobExecutor - MyJobExecutor executing...
21:03:25.680 [pool-2-thread-2] INFO c.t.m.e.s.e.p.p.MyJobExecutor - MyJobExecutor executing...
I was expecting MyJobScheduler to use 5 threads and MyJobScheduler2 to use 2 threads. It seems like both these Schedulers are using the same thread pool and getting limited to 2 threads rather than getting their own separate thread pools. What can be going on here?
I'm trying to figure out why my scheduled jobs are not executed parallelly. Maybe there is something wrong with my transaction management? Method JobScheduledExecutionService.execute() is #Scheduled with fixedRate=250, so it should be fired every 250ms no matter if previous job is finished. Due to logs it is not working as expected.
Logs: https://pastebin.com/M6FaXpeE
My code is below.
#Service
#Slf4j
public class JobExecutionService {
private final TransactionalJobExecutionService transactionalJobExecutionService;
#Autowired
public JobExecutionService(TransactionalJobExecutionService transactionalJobExecutionService) {
this.transactionalJobExecutionService = transactionalJobExecutionService;
}
public void execute() {
TestJob job = transactionalJobExecutionService.getJob();
executeJob(job);
transactionalJobExecutionService.finishJob(job);
}
private void executeJob(TestJob testJob) {
log.debug("Execution-0: {}", testJob.toString());
Random random = new Random();
try {
Thread.sleep(random.nextInt(3000) + 200);
} catch (InterruptedException e) {
log.error("Error", e);
}
log.debug("Execution-1: {}", testJob.toString());
}
}
#Service
#Slf4j
public class JobScheduledExecutionService {
private final JobExecutionService jobExecutionService;
#Autowired
public JobScheduledExecutionService(JobExecutionService jobExecutionService) {
this.jobExecutionService = jobExecutionService;
}
#Scheduled(fixedRate = 250)
public void execute() {
log.trace("Job fired");
jobExecutionService.execute();
}
}
#Service
#Slf4j
#Transactional
public class TransactionalJobExecutionService {
private final Environment environment;
private final TestJobRepository testJobRepository;
private final TestJobResultRepository testJobResultRepository;
#Autowired
public TransactionalJobExecutionService(Environment environment, TestJobRepository testJobRepository, TestJobResultRepository testJobResultRepository) {
this.environment = environment;
this.testJobRepository = testJobRepository;
this.testJobResultRepository = testJobResultRepository;
}
public TestJob getJob() {
TestJob testJob = testJobRepository.findFirstByStatusOrderByIdAsc(
0
);
testJob.setStatus(1);
testJobRepository.save(testJob);
return testJob;
}
public void finishJob(TestJob testJob) {
testJobResultRepository.save(
new TestJobResult(
null,
testJob.getId(),
environment.getProperty("local.server.port")
)
);
}
}
#Configuration
public class SchedulingConfigurerConfiguration implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(32);
taskScheduler.initialize();
taskRegistrar.setTaskScheduler(taskScheduler);
}
}
The reason is scheduler will fire only one event, which will be executed by one thread and then I don't see you are spawning multiple threads in your logic for parallel execution. That call of jobExecutionService.execute(); in execute() of JobScheduledExecutionService is in that one thread. So overall it ends up being sequential execution.
Seems you need to put multi-threaded [Callable-Future based] logic in JobExecutionService : execute() to pick job [transactionalJobExecutionService.getJob()] and call executeJob() inside it. hope this helps..
I am trying to create a Async REST Service using RestEasy, but I can't find any documentation that shows a clean way of doing so. The only example I found is here:
https://github.com/resteasy/Resteasy/blob/master/jaxrs/async-http-servlet-3.0/async-http-servlet-3.0-test/src/main/java/org/jboss/resteasy/test/async/JaxrsResource.java
#GET
#Produces("text/plain")
public void get(#Suspended final AsyncResponse response) throws Exception
{
response.setTimeout(2000, TimeUnit.MILLISECONDS);
Thread t = new Thread()
{
#Override
public void run()
{
try
{
System.out.println("STARTED!!!!");
Thread.sleep(100);
Response jaxrs = Response.ok("hello").type(MediaType.TEXT_PLAIN).build();
response.resume(jaxrs);
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
t.start();
}
Creating a new thread in the method doesn't seem like the best way to do things in a production environment. I feel like I should be getting a thread from a thread pool or something.
Any suggestions or links to better examples would be very helpful.
You are right about using Thread pool. Let Spring take care of it for you.
Assuming you are using Spring as a choice for your application you could do something like.
You can define an Configuration class for Async Executors.
#EnableAsync
#Configuration
public class AsyncConfiguration implements AsyncConfigurer {
#Inject
private Environment env;
#Bean
#Override
#Singleton
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(env.getProperty("controller.threadPoolTaskExecutor.corePoolSize", Integer.class, 10));
taskExecutor.setMaxPoolSize(env.getProperty("controller.threadPoolTaskExecutor.maxPoolSize", Integer.class, 100));
taskExecutor.setKeepAliveSeconds(env.getProperty("controller.threadPoolTaskExecutor.keepAliveSeconds", Integer.class, 60*5));
taskExecutor.setQueueCapacity(env.getProperty("controller.threadPoolTaskExecutor.queueCapacity", Integer.class, 10000));
taskExecutor.setThreadNamePrefix("controller-async-task-executor");
return taskExecutor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
}
Here is how you can define the Exception Handler:
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(AsyncExceptionHandler.class);
#Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
logger.error("Error processing async request in method: " + method.getName(), ex);
}
}
Here is how your controller could look like:
#Inject
private AsyncTaskExecutor asyncTaskExecutor;
#GET
#Produces("text/plain")
public void get(#Suspended final AsyncResponse response) throws Exception
{
response.setTimeout(2000, TimeUnit.MILLISECONDS);
asyncTaskExecutor.submit(() -> {
System.out.println("STARTED!!!!");
Thread.sleep(100);
Response jaxrs = Response.ok("hello").type(MediaType.TEXT_PLAIN).build();
response.resume(jaxrs);
});
}
I'm trying to setup a simple UDP server using Netty following the example here but using Spring for wiring dependencies.
My Spring config class:
#Configuration
#ComponentScan("com.example.netty")
public class SpringConfig {
#Value("${netty.nThreads}")
private int nThreads;
#Autowired
private MyHandlerA myHandlerA;
#Autowired
private MyHandlerB myHandlerB;
#Bean(name = "bootstrap")
public Bootstrap bootstrap() {
Bootstrap b = new Bootstrap();
b.group(group())
.channel(NioDatagramChannel.class)
.handler(new ChannelInitializer<DatagramChannel>() {
#Override
protected void initChannel(DatagramChannel ch) throws Exception {
ch.pipeline().addLast(myHandlerA, myHandlerB);
}
});
return b;
}
#Bean(name = "group", destroyMethod = "shutdownGracefully")
public NioEventLoopGroup group() {
return new NioEventLoopGroup(nThreads);
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
My server class:
#Component
public class MyUDPServer {
#Autowired
private Bootstrap bootstrap;
#Value("${host}")
private String host;
#Value("${port}")
private int port;
#PostConstruct
public void start() throws Exception {
bootstrap.bind(host, port).sync().channel().closeFuture().await();
/* Never reached since the main thread blocks due to the call to await() */
}
}
During the blocking call to await(), I don't see my application listening on the specified interface. I've tried to run the sample (setting up the server directly from the main function) and it works. I didn't find examples for setting up a UDP server using Netty and Spring.
Thanks, Mickael
EDIT:
In order to avoid blocking the Main thread (which is used for Spring configuration), I've created a new thread as follows:
#Component
public class MyUDPServer extends Thread {
#Autowired
private Bootstrap bootstrap;
#Value("${host}")
private String host;
#Value("${port}")
private int port;
public MyUDPServer() {
setName("UDP Server");
}
#PostConstruct
#Override
public synchronized void start() {
super.start();
}
#Override
public void run() {
try {
bootstrap.bind(host, port).sync().channel().closeFuture().await();
} catch (InterruptedException e) {
} finally {
bootstrap.group().shutdownGracefully();
}
}
#PreDestroy
#Override
public void interrupt() {
super.interrupt();
}
}
I can see the new thread is blocked waiting for Channel close (as in the example). The Main thread can continue Spring configuration. However, it still doesn't work.
There is no need to wait for termination of the channel in #PostConstruct. Try to remove await().