Best way to schedule a job in glassfish/centos - java

I need to run a daily job which will run once a day and get some data from a different database. The task is developed as an EJB. I tried the #Schedule with EJB, and it is working fine. But the issue is if there is a change in the schedule, the code has to be changed and the app to be redeployed. Is there a way to avoid this? May be by using configuration files etc. I am using JSF 2.2, glassfish3.4.2 in CentOS.

You can do this by creating your timer programmatically something like this
....
private static final String TIMER_NAME = "SOME_TIMER_NAME";
....
#Resource
TimerService timerService;
....
public void createTimer(String days, String hours, String minutes) {
removeTimer();
ScheduleExpression scheduleExpression = new ScheduleExpression();
if (days != null) {
scheduleExpression.dayOfMonth(datys);
}
if (hours != null) {
scheduleExpression.hour(hours);
}
if (minutes != null) {
scheduleExpression.minute(minutes);
}
TimerConfig timerConfig = new TimerConfig();
timerConfig.setInfo(TIMER_NAME);
Timer timer = timerService.createCalendarTimer(scheduleExpression, timerConfig);
}
private void removeTimer() {
for (Timer timer : timerService.getTimers()) {
if (TIMER_NAME.equals(timer.getInfo())) {
timer.cancel();
}
}
}
#Timeout
public void retrieveData() {
// retrieve data from DBs
}
now calling the createTimer method like this
createTimer("*", "3", null);
retrieveData() method will be executed at 3:00 AM each day. If you want to change the schedule you should call the method with appropriate values. You may tune it to meet your requirements like add input validation, define parameters differently etc. You may want to look at ScheduleExpression to find what is best for you. My code just shows an idea.

Did you consider using cron job?
here are some examples:
Cron examples

Related

TimerService null

I'm honestly missing something here. I have no idea how to make an instance of TimerService object. It is always null. I don't have a constructor because it's an Interface. I can't use the create methods. #Resource doesn't seem to allocate anything to it.
I'm trying to setup a simple programmatic timer that does a task every X minutes. The timeout duration can vary based on configuration which can change throughout runtime. I am using a WebLogic 12 web application.
What I have so far:
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
#Singleton
public class TimerBean {
#Resource
protected TimerService timerService;
public TimerBean(){
System.out.println("TimerBean constructor " + timerService);
}
#Timeout
public void timeoutHandler(Timer timer){
String name = timer.getInfo().toString();
System.out.println("Timer ticked. Name=" + name);
}
public void startOrModifyTimer(long initialExpiration, long interval, String name) {
System.out.println("Start or modify " + timerService);
}
}
This outputs:
TimerBean constructor null
& then after the server is running if I call start or modify:
Start or modify null
edit:
I got it to work by making the TimerBean #Singleton & #Startup & replacing constructor with #PostConstruct method.
however while it has an object for TimerService instantiated whenever I try to use its methods it gives me java.lang.IllegalArgumentException: Unknown bean state 0 for which there is no information...
If you're trying to use field injection, you're relying on the framework to come along after the object has already been instantiated and set the field, so it will always be null in the constructor. You can either do whatever logic you need in an #PostConstruct method or, my strong preference, inject the TimerService as a constructor argument instead of directly into the field.
#PostConstruct is never called. #Inject is not either (and Im unsure if I did it right)
I got it to work by making the TimerBean #Singleton & #Startup & replacing constructor with #PostConstruct method.
chrylis is right. From your description it looks like you instantiating TimerBean via constructor.
Result is that you manage life-cycle by yourself and container is not able to take care of this instance and inject anymore.
Inject your TimerBean into the class where you want to use it (Session for example), or use it as you did:
#Singleton
#Startup
public class TimerBean { .. }
Combination of these annotations basically create one instance of TimerBean during app server start sequence.
Btw. Constructor with #PostConstruct is wrong idea and it may behave really unpredictable during run-time (not sure if it is possible, but you creating circular instantiation with this combo).
I ended up using Timer & TimerTask for this. Couldn't figure TimerService out. Oh well. Seems to work fine.
For anyone curious:
long interval = minutes*60*1000;
long delay = interval;
if(prevTask != null){
delay = System.currentTimeMillis() - prevTask.scheduledExecutionTime(); //time left of previous setting
prevTask.cancel();
delay = interval - delay; //difference in time left & new interval
if(delay <=0) //if by new setting should've already ran, so run it ASAP...
delay = 2000;
logger.info(String.format("DB dump was already scheduled before. Set dump delay to %s minutes & setting new schedule to every %s minutes.", delay/60/1000, minutes));
}
TimerTask task = new TimerTask(){
private SimpleDateFormat ft = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss SSS");
private int minutes;
public TimerTask initialize(int minutes){
this.minutes = minutes;
return this;
}
public void run() {
try {
logger.info(String.format("Doing scheduled %s dump to DB. (Configured to occur every %s minutes.)", ft.format(new Date(this.scheduledExecutionTime())), minutes));
dumpToDB();
} catch (NamingException | SQLException e) {
e.printStackTrace();
}
}
}.initialize(minutes);
timer.schedule(task, delay, interval);
prevTask = task;

How To Call A Method After A Certain Period

I have a MySQL database running on my localhost. To this database I have JDBC-connection. Over a RESTful WebService a softwareagent puts results into this database. I implemented a garbage collector in Java and want to execute that garbage collector after a certain period. My aim is that I do not have too many entries in the table.
The Garbage Collector looks as follows:
public void collectGarbageResults() {
ArrayList<Integer> ids = new ArrayList<Integer>();
ResultSet rs = this.execQuery("SELECT * FROM results");
try {
while (rs.next()) {
if ( (System.currentTimeMillis()) - (Timestamp.valueOf(rs.getString("tmstmp")).getTime()) > Long.parseLong(appconfigs.get("resultstableactuality")) ) {
ids.add(rs.getInt("id"));
}
}
for (Integer i : ids) {
this.deleteResultsWhereId(i);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
The method I call looks as follows:
private void deleteResultsWhereId(int id) {
retint = this.updateQuery("DELETE FROM results WHERE id=" + id + ";");
}
I am using JSF in an Eclipse's Dynamic Web Project and these methods are implemented in a managed bean. I am going to store the interval in an XML-file which I use for my application's configuration. Over the variable appconfigs I call the method 'get' and ask for the node containing my interval.
Now my question:
How can I call the method of the garbage collector after a certain period in my WebApp?
If you have any questions do not hesitate to comment.
My Solution :
#WebListener
public class BackgroundJobManager implements ServletContextListener{
private ScheduledExecutorService scheduler;
#Override
public void contextInitialized(ServletContextEvent event) {
long delayToStart = 0;
long numberOfUnits = 60;
TimeUnit tu = TimeUnit.SECONDS;
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new ExecuteGarbageCollector(), delayToStart, numberOfUnits, tu);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
scheduler.shutdownNow();
}
}
The class I call implements Runnable as follows:
public class ExecuteGarbageCollector implements Runnable{
#Override
public void run() {
DAO dao = new DAO();
dao.collectGarbageResults();
}
}
You could use ScheduledExecutorService or Quartz
Quartz has a lot of facilities, but If you choose ScheduledExecutorService you don't have to add any new dependencies to your project. and as you just want this scheduled task, it's simple.
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(...);
Take a look at some comments about both in: Quartz vs. ScheduledExecutorService in Java web application
Check out a scheduler library. You can use Quartz for example.
Call Java from MySQL. You could either have this kicked off by a job or trigger
Just stick to SQL and ignore running this in Java. Probably the easiest if you are good at SQL. Then you can encapsulate this in a SPROC or trigger.
It's your choice whether this should live in your web-app or in your database. I've used both methods for executing timed SQL calls and tend to prefer the code oriented approach
The actual question could have well been how to call a function after a specific interval of time?
Take a look at :
How to call a method after some specific interval of time in Java
and
java: run a function after a specific number of seconds

EJB #Schedule wait until method completed

I want to write a back-ground job (EJB 3.1), which executes every minute. For this I use the following annotation:
#Schedule(minute = "*/1", hour = "*")
which is working fine.
However, sometimes the job may take more than one minute. In this case, the timer is still fired, causing threading-issues.
Is it somehow possible, to terminate the scheduler if the current execution is not completed?
If only 1 timer may ever be active at the same time, there are a couple of solutions.
First of all the #Timer should probably be present on an #Singleton. In a Singleton methods are by default write-locked, so the container will automatically be locked-out when trying to invoke the timer method while there's still activity in it.
The following is basically enough:
#Singleton
public class TimerBean {
#Schedule(second= "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() throws InterruptedException {
System.out.println("Called");
Thread.sleep(10000);
}
}
atSchedule is write-locked by default and there can only ever be one thread active in it, including calls initiated by the container.
Upon being locked-out, the container may retry the timer though, so to prevent this you'd use a read lock instead and delegate to a second bean (the second bean is needed because EJB 3.1 does not allow upgrading a read lock to a write lock).
The timer bean:
#Singleton
public class TimerBean {
#EJB
private WorkerBean workerBean;
#Lock(READ)
#Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
try {
workerBean.doTimerWork();
} catch (Exception e) {
System.out.println("Timer still busy");
}
}
}
The worker bean:
#Singleton
public class WorkerBean {
#AccessTimeout(0)
public void doTimerWork() throws InterruptedException {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
}
}
This will likely still print a noisy exception in the log, so a more verbose but more silently solution is to use an explicit boolean:
The timer bean:
#Singleton
public class TimerBean {
#EJB
private WorkerBean workerBean;
#Lock(READ)
#Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
public void atSchedule() {
workerBean.doTimerWork();
}
}
The worker bean:
#Singleton
public class WorkerBean {
private AtomicBoolean busy = new AtomicBoolean(false);
#Lock(READ)
public void doTimerWork() throws InterruptedException {
if (!busy.compareAndSet(false, true)) {
return;
}
try {
System.out.println("Timer work started");
Thread.sleep(12000);
System.out.println("Timer work done");
} finally {
busy.set(false);
}
}
}
There are some more variations possible, e.g. you could delegate the busy check to an interceptor, or inject a singleton that only contains the boolean into the timer bean, and check that boolean there, etc.
I ran into the same problem but solved it slightly differently.
#Singleton
public class DoStuffTask {
#Resource
private TimerService timerSvc;
#Timeout
public void doStuff(Timer t) {
try {
doActualStuff(t);
} catch (Exception e) {
LOG.warn("Error running task", e);
}
scheduleStuff();
}
private void doActualStuff(Timer t) {
LOG.info("Doing Stuff " + t.getInfo());
}
#PostConstruct
public void initialise() {
scheduleStuff();
}
private void scheduleStuff() {
timerSvc.createSingleActionTimer(1000l, new TimerConfig());
}
public void stop() {
for(Timer timer : timerSvc.getTimers()) {
timer.cancel();
}
}
}
This works by setting up a task to execute in the future (in this case, in one second). At the end of the task, it schedules the task again.
EDIT: Updated to refactor the "stuff" into another method so that we can guard for exceptions so that the rescheduling of the timer always happens
Since Java EE 7 it is possible to use an "EE-aware" ManagedScheduledExecutorService, i.e. in WildFly:
In for example a #Singleton #Startup #LocalBean, inject the default "managed-scheduled-executor-service" configured in standalone.xml:
#Resource
private ManagedScheduledExecutorService scheduledExecutorService;
Schedule some task in #PostConstruct to be executed i.e. every second with fixed delay:
scheduledExecutorService.scheduleWithFixedDelay(this::someMethod, 1, 1, TimeUnit.SECONDS);
scheduleWithFixedDelay:
Creates and executes a periodic action that becomes enabled first
after the given initial delay, and subsequently with the given delay
between the termination of one execution and the commencement of the
next.[...]
Do not shutdown the scheduler in i.e. #PreDestroy:
Managed Scheduled Executor Service instances are managed by the
application server, thus Java EE applications are forbidden to invoke
any lifecycle related method.
well I had a similar problem. There was a job that was supposed to run every 30 minutes and sometimes the job was taking more than 30 minutes to complete in this case another instance of job was starting while previous one was not yet finished.
I solved it by having a static boolean variable which my job would set to true whenever it started run and then set it back to false whenever it finished. Since its a static variable all instances will see the same copy at all times. You could even synchronize the block when u set and unset the static variable.
class myjob{
private static boolean isRunning=false;
public executeJob(){
if (isRunning)
return;
isRunning=true;
//execute job
isRunning=false;
}
}

Reset mysql colum values to default after specific using Servlet

I am new to web development I am making some web services using java servlets, and I am stuck in so many How to do it? stuff :(
I am developing an application in which I need to reset the mysql table column values back to default values at some time let's say we need to reset the counter # every Sunday 10:00 pm.
is there any thing like alarm manager in Java or mysql that can run all the time in background and trigger # specific time.
Thanks,
Java has a good interface ScheduledExecutorService.
You can try this code
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
//every day to execute
long everyDayDelay = 24*60*60*1000;
//first time to execute, it can be your special date
//for example 5 seconds after launch
long timeToExecute = System.currentTimeMillis()+5*1000;
service.scheduleWithFixedDelay(new Task(), getTimeToLaunch(timeToExecute), everyDayDelay, TimeUnit.MILLISECONDS);
where
//return difference between now and timeToExecute
public static long getTimeToLaunch(long timeToExecute){
long current = System.currentTimeMillis();
return timeToExecute - current;
}
class Task implements Runnable{
#Override
public void run() {
System.out.println("Run task!");
}
}
UPDATE: Class to execute your sql-tasks
public class SqlExecutionService1 {
public static final long everyDayDelay = 24*60*60*1000;
public SqlExecutionService1(){
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
//every day to execute
//first time to execute
//for example 5 seconds after launch
long timeToExecute = System.currentTimeMillis()+5*1000;
service.scheduleWithFixedDelay(new SqlTask1(), getTimeToLaunch(timeToExecute), everyDayDelay, TimeUnit.MILLISECONDS);
}
private long getTimeToLaunch(long timeToExecute){
long current = System.currentTimeMillis();
return timeToExecute - current;
}
}
class SqlTask1 implements Runnable{
#Override
public void run() {
//your sql tasks
}
}
To create this class, when your app server starts - use method init() in one of your main servlets.
Example -
public class MainInitServlet extends HttpServlet {
public void init() {
new SqlExecutionService1();
}
}
The Data of a Database should be the basis for calculation, not the result of calculations. In example Bills wont ever be successfully revised.
I guess this fact will ever be a clash between Programmers and Architects.
you might also use the event scheduling mechanism of mysql
this depends on the version of mysql and whether it is enabled or not
is there any thing like alarm manager in Java or mysql that can run all the time in background and trigger # specific time.
look at a API called Quartz , where your program can schedule Jobs and it will run it at that time.
use method execute(JobExecutionContext jobExecution) use to fire trigger.
EG:
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
// Retrieve scheduler
Scheduler scheduler = null;
try {
scheduler = schedulerFactory.getScheduler();
}
catch (SchedulerException e) {
e.printStackTrace();
}
//this is a job
JobDetail job = new JobDetail("jobDetail", "jobDetailGroup", ImplementedJob.class);
SimpleTrigger trigger = new SimpleTrigger("Trigger Name","defaultGroup", DATE);
// schedule
scheduler.scheduleJob(job, trigger);
// start the scheduler
scheduler.start();

Schedule task depending on its response

I'm trying to schedule a task depending on it's response. The task is something like:
public Date scheduledTask() {
Date nextRun;
// ...
nextRun = something();
// ...
return nextRun;
}
How can I make sure that the same task is called again when reaching the nextRun?
Thank you.
This is very simple with standard Quartz scheduler API. Inside your Job compute nextRun time and create a trigger with startAt() defined:
public class ScheduledJob implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
final Date nextRun = something();
Trigger trigger = newTrigger().
startAt(nextRun).
forJob(context.getJobDetail()).
build();
context.getScheduler().scheduleJob(trigger);
}
}
Tested, works like a charm.
Follow the ideas mentioned here, then you should be able to have:
public class GuaranteeSchedule implements Trigger {
private Future<?> resultForNextRun;
private TaskScheduler scheduler;
public void scheduledTask() {
// 'this' is this trigger that is used by the scheduler
// and the method `nextExecutionTime` is automatically called by the scheduler
resultForNextRun = scheduler.schedule(theTask, this);
// theTask is the object that calls something()
}
// Implementing Trigger to add control dynamic execution time of this trigger
#Override
public Date nextExecutionTime(TriggerContext tc) {
// make sure the result for the previous call is ready using the waiting feature of Future
Object result = resultForNextRun.get();
// Use tc or other stuff to calculate new schedule
return new Date();
}
}
The rest, you should follow the configuration mentioned in the reference. I believe this would resolve the problem of depending the next call of a trigger on the result of the previous. You may also need to be careful about the first call of scheduledTask to make sure resultForNextRun != null.

Categories