I need to execute a task every 5 minutes on my server to update some datas on a db, i've found that on openshift i have the cron that executes some script every tot time. Is it possibile to make a script that makes a simple call to a servlet or to a java code to run this job?
I am quite new to server side programming so please speak easy!
Ps. I am using a Tomcat 6 (Jboss EWS 1.0), mySQL 5.5 server
AS I understand you, you need your application to run sth every XX minutes.
To calculate the start time I made a helper function "getStartTime" With that I can use the human readable time like "23:30" (attention, I am from german, so it is not for AM/PM, just change for your needs).
Helper Method:
private static long getStartTime(String startTime) {
int hour = Integer.parseInt(startTime.split(":")[0]);
int minutes = Integer.parseInt(startTime.split(":")[1]);
Calendar cal = Calendar.getInstance();
Date dateNow = cal.getTime();
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minutes);
cal.set(Calendar.SECOND, 0);
if(cal.getTime().before(dateNow)) {
cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH) + 1);
return cal.getTime().getTime();
} else {
return cal.getTime().getTime();
}
}
Now you can use the ScheduledExecutorService from Java. Example:
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
long startClearRequests = getStartTime(DEFAULT_JOB_START_TIME) - System.currentTimeMillis();
And set your needs into the scheduleAtFiexed Rate:
scheduledExecutorService.scheduleAtFixedRate(clearRequests, startClearRequests, Math.round(DEFAULT_JOB_PERIOD_HOURS * 60 * 60 * 1000), TimeUnit.MILLISECONDS);
For example I use:
private static final int NUM_OF_THREADS = 2;
private static final String DEFAULT_JOB_START_TIME = "23:30";
private static final double DEFAULT_JOB_PERIOD_HOURS = 24;
As you see, you can change the number of threads (depends of what your application is doing), the start time (this is just needed for application start (when to start the job the first time).
And also the period (every XX hour the job shall run ... I took hours, but you need ti insert milliseconds at the end, so for 5 minutes (you have to tak 5 * 60 *1000 miliseconds.
Greetings
EDIT in respect to the athors comments:
To start things on application start, you have several methods. One method is to start a servlet on startup like this. Insert into the web.xml
<servlet>
<servlet-name>ServletStartups</servlet-name>
<servlet-class>model.initialization.ServletStartups</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
This will call the Class ServletStartups on Application start (the number in load-on-startup is the priority, because you can have multiple entries and can decide which to start first (1, 2, 3 ...)
Now within your servlet you defines an init() method, which is automatically called, like that:
public class ServletStartups extends HttpServlet{
public void init() throws ServletException{
// HEre you can put your methods as described above //(scheduledExecutorService( ...
}
}
IMPORTANT NOTE:
above I had a method "clearRequests", sorry this was my method, I have not renamed it to add it here. THis method will be called in my application every 24 hours.
the methods you call from the ScheduledExecutorService have to be a callable, like this:
private Runnable clearRequests = new Runnable() {
public void run() {
try {
// Here do your task
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
Related
I have a scheduler(using #Scheduler) running between 7 to 9 PM for every 15 mins. It looks for a file every 15 mins. If the file is found then the scheduler should stop for today and run next day again. How to achieve this in spring boot?
Probably the easiest way is to implement it at the level of business logic.
Spring provides a way to run a periodic task, that's true, but it can't stop the job for some time if a business case is met (the file is found).
Having said that, you could implement the scheduled job as follows:
#Component
public class MyScheduledJob {
private LocalDateTime runNextTime = null;
private boolean isFileFound = false;
#Scheduled(/**here comes your original cron expression: 7 am to 9 pm with an interval of 15 minutes as you say **/)
public void runMe() {
if(isFileFound && LocalDateTime.now().isBefore(runNextTime)) {
// do not run a real job processing
return;
}
isFileFound = checkWhetherFileExists();
if(isFileFound) {
runNextTime = calculateWhenDoYouWantToStartRunningTheActualJobProcessingNextTime();
}
... do actual job processing... Its not clear from the question whether it should do something if the file is not found as well, but I'm sure you've got the point ...
}
}
Since the bean is a singleton you can safely create a state for it, no-one won't change that state anyway.
You can do something like this. You can write your logic for checking files inside this method.
#Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void scheduleFixedRateWithInitialDelayTask() {
long now = System.currentTimeMillis() / 1000;
System.out.println(
"Fixed-rate task with one-second initial delay - " + now);
}
See this for more details.
I’m currently using selenium in a web bot to purchase items on a website. When I search for the item I want to buy and it cannot be found I use driver.navigate().refresh() to refresh the page to see if it is there now, it will keep doing this until it finds the product when it is released on the page. However, I wish to start my bot a few hours before the release of the product which currently doesn’t work as after roughly 30 seconds of refreshing the page I get banned from the page due to the anti-ddos software they use. One option is to increase the delay between refreshing, however I need to catch the release of this product as soon as possible so I’m trying to find a way that my program can wait/sleep until 30 seconds before the release however I’m struggling to find a way to do this.
Just call Thread.sleep with the appropriate amount of milliseconds:
public static void main(String[] args) throws InterruptedException {
long currentTime = System.currentTimeMillis();
long releaseTime = currentTime + 1000 * 60 * 60 * 24 * 3; // 3 days
Thread.sleep(releaseTime - currentTime);
}
Another way would be to use java.time classes:
public static void main(String[] args) throws InterruptedException {
LocalDateTime now = LocalDateTime.now();
LocalDateTime release = LocalDateTime.of(2019, 10, 30, 13, 30);
long sleepDuration = Duration.between(now, release).toMillis();
TimeUnit.MILLISECONDS.sleep(sleepDuration);
}
Java 9 introduces new methods to the Duration class like toSeconds(), toMinutes() and so on.
You could also consider using a ScheduledExecutorService to schedule your tasks. This is especially useful if you have multiple tasks to schedule and don't want having multiple threads being blocked for that:
private static final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(2);
private static ScheduledFuture<?> scheduleTask(Runnable task, LocalDateTime releaseTime) {
Duration duration = Duration.between(LocalDateTime.now(), releaseTime);
return service.schedule(task, duration.toSeconds(), TimeUnit.SECONDS);
}
In general, to sleep until the next Thursday at 10:59 you could use the following code:
LocalDateTime release = LocalDateTime.now()
.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY))
.withHour(10)
.withMinute(59);
Duration duration = Duration.between(LocalDateTime.now(), release);
TimeUnit.MILLISECONDS.sleep(duration.toMillis());
I think rather than sleeping you should take a look at scheduled tasks with cron expressions in Spring... that way you don't have a blocked thread just sitting there.
Scheduled Tasks with Spring
Cron Expressions
I have a scheduled task using SpringBoot Scheduled to run Monday through Friday at 10 AM.
I'm running my application in a docker container and my machine is suspended from 6pm to 9am overnight.
When I start my machine, my tasks that were scheduled for 10 hours do not run unless I restart the container before the scheduled time.
I have application logs, no log record occurs that is inside the method with the #Scheduled annotation when this occurs.
With that I believe it's a deadlock.
I wonder if there is any way to detect a deadlock in the Springboot Scheduled programmatically.
My Cron expression: "0 0 10 * * MON-FRI"
Note: I'm testing on my machine to later host on an appropriate server.
AFAIK there is no standard way in Java to detect if the system went in standby/hibernate. Scheduling in Spring is based on the timing facilites in Java, facilites which are not intended to work across OS sleep or hibernate conditions. In short, if the JVM cannot detect when system goes in standby neither can Spring.
As I see it you have the following options:
notify the application when the system is resumed then re-schedule the tasks. This is a possible solution built around pm utils on Ubuntu. This one is for Windows.
add an additional task that runs, say every 10 seconds and reads the system time. If there is an appreciable difference between two time readings it means your system went to sleep and then resumed.
The following for example restarts the context if a time gap (delta) greater than 1s is detected:
#SpringBootApplication
#EnableScheduling
public class Application {
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(Application.class, args);
}
static LocalTime lastDetectedTime;
static long delta = 1000;
static final long CHECK_INTERVAL = 5000;
#Scheduled(fixedDelay = CHECK_INTERVAL, initialDelay = CHECK_INTERVAL)
public static void restartIfTimeMismatch() {
if(lastDetectedTime == null) {
lastDetectedTime = LocalTime.now();
}
LocalTime currentTime = LocalTime.now();
long diff = Duration.between(lastDetectedTime, currentTime).toMillis();
lastDetectedTime = currentTime;
if(diff > CHECK_INTERVAL + delta) {
Thread thread = new Thread(() -> {
context.close();
context = SpringApplication.run(Application.class);
});
lastDetectedTime = null;
thread.setDaemon(false);
thread.start();
}
}
}
Hope it helps.
Right now my program accepts an input, and formats it into a Date. But I want it to call a method whenever that date is reached. How could I do this without the use of any libraries like Quartz?
Code I have for the input:
Date date = new Date();
String inputDate;
month = (String) comboBoxMonth.getSelectedItem();
day = Integer.parseInt((String) comboBoxDay.getSelectedItem());
hours = Integer.parseInt((String) comboBoxTimeH.getSelectedItem());
minutes = Integer.parseInt((String) comboBoxTimeM.getSelectedItem());
try {
//Month/Day/Year Hour:minute:second
inputDate = month + "/" + day + "/" + year + " " + hours + ":" + minutes;
date = formatter.parse(inputDate);
} catch (ParseException e) {
e.printStackTrace();
}
You can use Timer and TimerTask object.
Timer timer = new Timer ();
TimerTask myTask = new TimerTask () {
#Override
public void run () {
// call your method here
}
};
// Schedule the task. Start it when your date is reached!
timer.schedule(myTask, yourDate);
Timer object allow you to handle multiple TimerTask instance!
After the line where you parse the date, add t.schedule(task, date), where 't' is a Timer, and 'task' is a TimerTask that represents the method you want to be executed at the given date.
The Timer class mentioned in another Answer is the old way.
Executor
As of Java 5, the modern way is the Executors suite of interfaces and classes, specifically the ScheduledExecutorService.
Be sure to read up, including searching StackOverflow for more info. Specifically, be aware that any uncaught exception bubbling up to your main code running in the Executor will cause service to cease. Any future scheduled runs of your code will be terminated. The solution is simple: Always surround the main code of your executor with a try-catch to catch any Exception (and maybe even Error, or, Throwable).
Never Use Timer In Servlet/JaveEE
Most especially, do not use Timer in a Servlet or Java EE (Enterprise Edition) app. See this Answer by BalusC for details.
i want to run the ejb timer every 2 hrs between 9-18 and btw mon-sat and on friday btw 9-14 and on sat 9-13
if it is possible that on friday timers run after ever 1 hr
how can i do this with ejb timer
#Singleton
#Startup
public class TimedBean{
#Resource
private TimerService service;
#PostConstruct
public void init(){
ScheduleExpression exp=new ScheduleExpression();
exp.hour("*")
.minute("*")
.second("*/30");
service.createCalendarTimer(exp);
}
#Timeout
public void timeOut(){
System.out.println(new Date());
System.out.println("time out");
}
}
also note that according to me this code will run after every 30 sec , but problem is it is called 2-3 times after every 30 sec
any help is appreciated
If I understand you correctly, you can create Timers to do all of those things:
ScheduleExpression exp;
exp = new ScheduleExpression().minute(0).second(0);
exp.dayOfWeek("mon-sat").hour("9,11,13,15,17");
service.createCalendarTime(exp);
exp = new ScheduleExpression().minute(0).second(0);
exp.dayOfWeek("fri").hour("9-14");
service.createCalendarTime(exp);
exp = new ScheduleExpression().minute(0).second(0);
exp.dayOfWeek("sat").hour("9,11,13");
service.createCalendarTime(exp);
There are some conflicts in the above timers, but that seems to be what you're asking for. You may want to stagger them by giving each a different minute of the hour; for instance, you may want the second to use minute(20) and the third to use minute(40).
Reference: ScheduleExpression documentation