Java - Scheduling tasks in Jboss & without EJB - java

My java web application that uses spring for dependency injection is packaged in an EAR and is deployed in Jboss 7, but has no EJB. The application is installed on two load balancing machines. I need to schedule a method to run daily, but that method can't run at the same time on both instances.
I tried to use Spring's Scheduling annotations, but the problem is that, as there is load balancing, the scheduled method runs twice (once in each cluster).
What is the best way to do this in Jboss 7? Can someone help me ?
The method to be scheduled looks like the one below.
public synchronized void processor() {
LOGGER.info("start");
//processing logic
LOGGER.info("the end");
}
Thanks a lot!!!

Well, considering the requirements: two or more apps and they need to be synchronized, you need either #Singleton or #Stateless EJB, described here.
Invoking it via the timer service, then it needs to be an EJB with #Timer on some method and if you use #Scheduled or such on a method, then it will invoke that method
On this case a Singleton is recommended, otherwise, you might end up with multiple instances of the same timer running.
Example
#Example
private void init()
{
ScheduleExpression Expression = new ScheduleExpression();
#This means twice per hour {0,2,4, ... 22} ~ since it ends on 23h:
expression.second(0).minute(0).hour(*/2).month(*).dayOfWeek(*);
stopTimer();
Timer timer = service.createCalendarTimer(exp);
}
Any other suggestion seems to add too much complexity.

Related

How do you separate roles in Spring Boot ? (Web vs Scheduler, etc..)

I am coming from a (mostly) Python Django/Celery background and starting with Spring Boot.
I am having a hard time to understand how do you separate the roles.
For example when having a Django/Celery project, I will have one one side the web backends started as gunicorn, and on the other side the workers started as celery (so, different commands, but pointing at the same code).
But on Spring Boot, you only have a single entrypoint, and as soon as the scheduler is injected, the jobs will start being processed.
What is the correct way do separate those like in a Django/Celery application ?
Should I put almost all my code as a library and then create 2 final applications, one that will setup the #DispatcherServlet and another one that will setup #EnableScheduling, or is there some kind of configuration to be injected at runtime ?
In my opinion, if 'the web' and 'the scheduler' are both the important function in the application, then we don't need to separate them as long as you are creating a monolithic application.
Because you are using spring boot, so #DispatcherServlet and all the other web component that a web application needed will be injected and configured automatically. The only thing you have to do is creating some class that annotated with #Controller or #RestController and set up the #RequestMapping methods inside those class.
How about Scheduler? you need to add #EnableScheduling in one of the #Configuration class first, then create Scheduler class in scheduler package like below code sample.
You can use cron property to set up the specify execute time just like Linux crontab. The jobs will start being processed only if the cron time is up.
#Component
public class PlatformScheduler {
#Autowired
private BatchService batchService;
#Scheduled(cron = "0 0 12 * * *")
public void dailyInitialize() {
clearCompletedBatches();
queryBatchesToRunToday();
}
#Scheduled(fixedRate = 10000, initialDelay = 10000)
private void harvestCompletedBatches() {
batchService.harvestCompletedBatches();
}
#Scheduled(fixedRate = 10000, initialDelay = 10000)
private void executeWaitingBatches() {
batchService.executeWaitingBatches(new DateTime());
}
}
The most simple project hierarchy will be like below, 'the web' and 'the scheduler' can be in the same project safely and share the same #Service components without harm.

Cancel timer in lifecycle callback of singleton bean

I have an Java EE project running Wildfly 10.1 Final.
I am creating some timers programmatically using javax.ejb.TimerService like this:
timerService.createTimer(new Date(), null);
And now, I am trying to cancel those timers the next time the project is deployed, because they are still there every time I re-deploy the project, or restart the server.
I tried to use a Singleton Startup bean for that, like this:
#Startup
#Singleton
public class TimerKiller {
#PostConstruct
public void killTimers() {
timerService.getAllTimers().forEach(timer -> timer.cancel());
}
#Resource
TimerService timerService;
}
But, I get an exception:
java.lang.IllegalStateException: WFLYEJB0325: Cannot invoke timer
service methods in lifecycle callback of non-singleton beans
This is the last exception in the stack trace (the last Caused By).
I can't seem to understand what does this mean. I tried googling but nothing comes up.
Did you use javax.ejb.Singleton or javax.inject.Singleton. Make sure you are using javax.ejb.Singleton.
You can also use a e.g. SingleActionTimer and specify it as non-persistent:
TimerConfig tc = new TimerConfig(null, false);
timerService.createSingleActionTimer(new Date(), tc);

Making #Schedule run only once in a clustered environment

I have two tomee instances clustered.
Each one have a method annotated like
#Schedule(dayOfWeek = "*")
public void runMeDaily() {...}
I'd like to run this method only once a day. Not twice a day (one on each instance)
I could use a flag as described here Run #Scheduled task only on one WebLogic cluster node? or just elect some node, but I wonder if there's a more elegant way to do that.
This question is somewhat related to EJB3.1 #Schedule in clustered environment but I am not using JBOSS. (and it's not answered)
Im using same approach as in other thread - checking that particular host is the correct one to run job. But..
Im not very info ee tools, but in spring you can use profiles for that. Probably you can find similar solution for your needs. Take a look at http://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles
You can define two seperate beans:
#Configuration
#Profile("dev")
public class StandaloneDataConfig {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
#Configuration
#Profile("production")
public class JndiDataConfig {
#Bean
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
and decide which one to turn on by switching profile. So your class with method annotated #Scheduled would be loaded only for specific profile. Ofcourse then you need to configure your app to turn on profile on of the nodes only. In spring app it would be as simple as passing -Dspring.profiles.active=profile to one of them.
I could only solve this using a non-Java EE solution, specific to the platform (proprietary). In my case, I am using TomEE+ and Quartz. Running Quartz in the clustered mode (org.quartz.jobStore.isClustered = true) and persisting the timers in a single database forces Quartz to choose an instance to trigger the timer, so it will only run once.
This link was very useful -- http://rmannibucau.wordpress.com/2012/08/22/tomee-quartz-configuration-for-scheduled-methods/
It's a shame Java EE does not specify a behavior for that. (yet, I hope) :-)
I solved this problem by making one of the box as master. basically set an environment variable on one of the box like master=true.
and read it in your java code through system.getenv("master"). if its present and its true then run your code.
basic snippet
#schedule()
void process(){
boolean master=Boolean.parseBoolean(system.getenv("master"));
if(master)
{
//your logic
}
}

Java EE 7 Automatic Timer (EJB Timer) not working for WildFly 8.1.0

I am following the Using the Timer Service tutorial to build a simple scheduled execution. Trying the automatic approach and using WildFly 8.1.0 Final for it.
Session Bean
#Singleton
#Startup
public class HelloJob {
private static final Logger logger = Logger.getLogger(HelloJob.class);
public HelloJob() {
logger.error(">>> Hello Job Created.");
}
#Schedule(second="*")
public void sayHello() {
logger.error(">>> Server Hello!");
}
}
On deploy the class is properly instantiated printing the >>> Hello Job Created. message, but the method sayHello() is never called.
According to the tutorial the #Schedule(second="*") means that it should execute every second.
Setting an attribute to an asterisk symbol (*) represents all
allowable values for the attribute.
Also only stateful session beans are not allowed for timers, and I am using a singleton, which is also used in the example.
The timer service of the enterprise bean container enables you to
schedule timed notifications for all types of enterprise beans except
for stateful session beans.
Use #Schedule(second="*", minute="*", hour="*").
the default values for hour and minute are "0" which can be quite irritating and effectively forces you to set these.

How to wait to another bundle?

I am developing an OSGi application which is composed by several bundles. All of them depend on the EventAdmin one. However, one specific plug-in has to start up a scheduled task as soon as the bundled is started (i.e. in the start method of the activator). The problem is that the event admin service is not still registered and I should wait for the deployment of this. I would not like to do this through the config properties file, therefore, is there any operation to do this without the properties file of Felix?
Thanks a lot in advance
There is no start ordering in OSGi ... get over it ... Though there are mechanisms to influence the initial start ordering, the problem is that any bundle can stop at any time. So the ONLY solution is to actually handle your dependency on Event Admin.
With Declarative Services (DS), this is actually very little work. Also, please forget bundle activators, they are bundle singletons and are thus a bad idea. So in DS you would do the following (using the annotations):
#Component(immediate=true)
public class MyTask extends Thread {
EventAdmin ea;
public void run() {
while ( !isInterrupted()) {
// do something
ea.postEvent(...);
}
}
#Activate void activate() { this.start();}
#Deactivate void deactivate() { this.interrupt(); }
#Reference void setEventAdmin(EventAdmin ea) { this.ea = ea;}
}
There are rare cases you should not use DS and are stuck with Bundle-Activators, but they are rare and should become rarer. If you're stuck with such a really bad case, then you can also create a service tracker in the Bundle Activator start method and track Event Admin services. Once you get one, you create a thread to run your code. When the service disappears you interrupt the thread. However, this is a much more complex solution.
There are also other service dependency manager but I strongly recommend Declarative Services with their annotations.
I have used iPOJO for this. It is designed to be used in felix & karaf. This library understands the lifecycle and dependencies of components and you will be notified via #Validate and #Invalidate methods when a components dependencies are available or one or more goes away.
It also support #Bind and #Unbind when an implementation of a service (an interface) appears or disappears. This make subscriptions much simpler.
You have a listener to a service and this component #Provides an interface to be called. The central event register will then be called on its #Bind method when such a component appears and #Unbind when it goes away for any reason.
I suspect iPOJO should do all the dependency management and binding you need.

Categories