i am not really familiar with Spring's Live Reload feature. However, i noticed that every time i have changes saved on my Java code. Java profiles (JMC) or Eclipse's (Debug Mode) shows that the thread i already spawned was spawned again resulting on 2 threads (1 thread before reload + 1 thread after reload).
I am currently using ThreadPoolExecutor to spawned my threads. basically i am letting spring manage my threads. In this case, How to i force shutdown/interrupt the threads i spawned when there is live reload occuring?
Below is my source.
ApplicationThreadingConfiguration.java
#Configuration
public class ApplicationThreadingConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ApplicationThreadingConfiguration.class);
#Autowired
MyProperties prop;
#Bean(name = "myThread")
public TaskExecutor taskExecutor() {
logger.info(prop.toString());
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(prop.getCorePoolSize());
executor.setMaxPoolSize(prop.getMaxPoolSize());
executor.setQueueCapacity(prop.getQueueCapacity());
executor.setThreadNamePrefix("MyThread-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
}
AppEventConfiguration.java (this spawns my thread after Spring context is loaded)
#Configuration
public class AppEventConfiguration {
private static final Logger logger = LoggerFactory.getLogger(AppEventConfiguration.class);
#Autowired
private MyService service;
#Autowired
private ApplicationContext context;
#Autowired
#Qualifier("myThread")
private TaskExecutor executor;
#EventListener(ApplicationReadyEvent.class)
public void onApplicationReadyEvent() {
service.getSomethingFromDB().stream().forEach(dto -> {
logger.info("Id: {}", dto.getId());
MyRunnableThread t = this.context.getBean(MyRunnableThread.class);
t.setMyId(dto.getId());
executor.execute(t);
});
}
}
MyRunnableThread.java
#Component
#Scope("prototype")
public class MyRunnableThread implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(MyRunnableThread.class);
private long myId;
#Override
public void run() {
while(true) {
try {
logger.info("Do something here on ID: {}",this.myId);
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void setMyId(long id) {
this.myId = myId;
}
}
myproperties.properties
myprop.core-pool-size=80
myprop.max-pool-size=100
myprop.queue-capacity=100
Related
I have created a simple service like ... where I have to take some data from database at later
package com.spring.scheduler.example.springscheduler;
import org.springframework.stereotype.Service;
#Service
public class ExampleService {
private String serviceName;
private String repository;
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getRepository() {
return repository;
}
public void setRepository(String repository) {
this.repository = repository;
}
}
Here is my task scheduler created to run different threads.
#Component
public class TaskSchedulerService {
#Autowired
ThreadPoolTaskScheduler threadPoolTaskScheduler;
public ScheduledFuture<?> job1;
public ScheduledFuture<?> job2;
#Autowired
ApplicationContext applicationContext;
#PostConstruct
public void job1() {
//NewDataCollectionThread thread1 = new NewDataCollectionThread();
NewDataCollectionThread thread1 = applicationContext.getBean(NewDataCollectionThread.class);
AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(thread1);
factory.initializeBean(thread1, null);
job1 = threadPoolTaskScheduler.scheduleAtFixedRate(thread1, 1000);
}
}
This is a thread trying to call from scheduler. I tried to create service instance forcibly by using application context but it's not created.
#Configurable
#Scope("prototype")
public class NewDataCollectionThread implements Runnable {
private static final Logger LOGGER =
LoggerFactory.getLogger(NewDataCollectionThread.class);
#Autowired
private ExampleService exampleService;
#Override
public void run() {
LOGGER.info("Called from thread : NewDataCollectionThread");
System.out.println(Thread.currentThread().getName() + " The Task1
executed at " + new Date());
try {
exampleService.setRepository("sdasdasd");
System.out.println("Service Name :: " +
exampleService.getServiceName());
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Kindly suggest what are the possible ways to achieve it.
Try something like this:
#Autowired
private AutowireCapableBeanFactory beanFactory;
#PostConstruct
public void job1() {
NewDataCollectionThread thread1 = new NewDataCollectionThread();
beanFactory.autowireBean(thread1);
job1 = threadPoolTaskScheduler.scheduleAtFixedRate(thread1, 1000);
}
In NewDataCollectionThread I injected the Example service successfully.
It is the first time i use concurrency with Spring and i have a piece of code that makes concurrent calculations using Spring. Here is the code :
#Component
public class AppScheduler {
//#Autowired DAOs or services.
private ThreadPoolExecutor executor;
private AbstractApplicationContext context;
#PostConstruct
public void init() {
executor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(10));
context = new AnnotationConfigApplicationContext(VtmDispatcherConfig.class);
}
#Scheduled(fixedDelay = 60 * 1000)
//at rejection break the execution.
public void appEntry() {
//fetch some records from db
for (Record rec : records) {
try {
executeTransactionally(rec);
} catch (RejectedExecutionException ex) {
break;
}
}
}
#Transactional
//Creates runnable tasks, makes some db operations and passes task to the thread pool
private void executeTransactionally(Record rec) {
ARunnableTask aRunnableTask = (ARunnableTask) context.getBean("aRunnableTask");
aRunnableTask.setParameter(rec.param);
//some db operations...
tempTableExecutorPool.execute(aRunnableTask);
}
}
Here a scheduled code fetchs records from db and with each record instantiates a runnable task and passes it to the thread pool executor. And my runnable task is here :
#Component
#Scope("prototype")
public class ARunnableTask implements Runnable {
private String param;
private ThreadPoolExecutor executor;
private DAOOrService inject
#Autowired
public TempTableExecutorTask(DAOOrService inject) {
executor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1000));
this.inject = inject;
}
#Override
public void run() {
//...
executeTransactional();
//...
executor.shutdown();
}
#Transactional
private void executeTransactional() {
//some transactional processes
}
public void setParameter(String param) {
this.param = param;
}
}
and here is my question : Is it a good practice creating runnable tasks as a spring component and using #Transactional in a runnable?
If it is not a bad practice, is there a better way for creating runnable spring components than :
ARunnableTask aRunnableTask = (ARunnableTask) context.getBean("aRunnableTask");
aRunnableTask.setParameter(rec.param);
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'm writing a Spring-Boot application to monitor a directory and process files that are being added to it. I start a thread by creating a ApplicationRunner in my Application class that calls a method annotated with #Async:
#SpringBootApplication
#EnableAsync
public class Application {
#Autowired
private DirectoryMonitorService directoryMonitorService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ApplicationRunner startDirectoryMonitorService() {
return args -> directoryMonitorService.monitorSourceDirectoty();
}
}
Here is the code for DirectoryMonitorService that has a method annotated with #Async:
#Service
public class DirectoryMonitorService {
private static final Logger logger = LogManager.getLogger(DirectoryMonitorService.class);
#Value("${timeout}")
private long timeout;
#Autowired
private WatchService watchService;
#Async
public void monitorSourceDirectoty() {
while (true) {
WatchKey watchKey;
try {
watchKey = watchService.poll(timeout, TimeUnit.SECONDS);
} catch (ClosedWatchServiceException | InterruptedException e) {
logger.error("Exception occured while polling from source file", e);
return;
}
// process the WatchEvents
if (!watchKey.reset()) {
break;
}
}
}
}
Finally here is where I create the ThreadPoolTaskExecutor:
public class AsyncConfig extends AsyncConfigurerSupport {
private static final Logger logger = LogManager.getLogger(AsyncConfig.class);
private static final String THREAD_NAME_PREFIX = "Parser-";
#Value("${corePoolSize}")
public int corePoolSize;
#Value("${maxPoolSize}")
public int maxPoolSize;
#Value("${queueCapacity}")
public int queueCapacity;
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (Throwable ex, Method method, Object... params) -> {
logger.error("Exception message - " + ex.getMessage());
logger.error("Method name - " + method.getName());
for (Object param : params) {
logger.error("Parameter value - " + param);
}
};
}
}
Somehow I feel this is not most elegant way of starting a main thread. Does anybody have a better solution?
Also I would rather have replace while (true) with a Boolean variable that I can set to false when Spring-Boot shuts down. Does anybody know which interface I need to implement for this?
This is correct if you want a very simple implementation and nothing more reliable.
Use #Async to a shorter tasks and it has very limited capability in terms of restarts etc.
And also, #Async will keep creating the separate threads at every watch sequence activation, and it will overwhelm the thread pool and start trowing exceptions, This is quite noticeable, if you have long running task as,
// process the WatchEvents
Other than that your implementation is correct (In my opinion).
Some suggestions (If you want to make things interesting/ complex):
So you can keep track of the files obviously using some sort of persistence mechanism and trigger decoupled batch (can use Spring Batch) to handle the execution and, get those batches into a separate UI or something and there you can have each of these batch process stopped, start, resume on the UI.
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().