I hope you can advise me.
I have a Spring Boot API and a mobile app. I have to send push notifications to the users one hour before they have to do something, like a reminder. I have the specific date and time stored in a database.
I've been reading about scheduled tasks but I don't like it at all.
So, what do you think is the best way to do this?
I've been reading about scheduled tasks but I don't like it at all.
How else should it work? You need some kind of Scheduler / Timer that triggers your code at the specified time.
You could go for the simplest solution that came to my mind:
long delay = ...; // calculate the delay when the code should be executed
Runnable theCodeToExecute = () -> System.out.println("hello world");
new Thread(() -> {
try {
Thread.sleep(delay);
runnable.run();
}
catch (Exception e){
System.err.println(e);
}
}).start();
This of course has several disadvantages: When you restart your app, the scheduled task is gone. And it won't be very efficient when you have hundreds of threads sleeping.
There are of course ways to circumvent this:
Store your timers in a database (or in a file). And remove the entries when you sent the notification. And when your application restarts, you simply read the stored entries and restart the timers.
You could use a Queue (or sorted List) of tasks. And have a single Thread, that looks every N seconds for the next task in the queue. If this task is ready, remove it from the Queue (or List) and execute the code.
As an alternative, you can of course use a Framework that already does all of this for you, like for example Quartz
Related
I want a mechanism that will start a java program ( quite a big one ) depending on 2 conditions:
N new inserts in a MySQL table
Every 5 minutes interval.
I know that I can do this through crontab or using Timer or using Stored Procedure etc.
My plan is to write a Java class ( I am most familiar with ), Listener having two threads in parallel - Database Listener and Time listener threads each of them monitoring one of these conditions. If one says, yes, the parent class will start a new thread to run the Program.
I feel that it will be a heavy weight program. Is there some other option that I am overlooking at?
Write a single job. Have it execute regularly.
Effectively, you'll be doing some something of the nature of:
SELECT count(*) FROM table WHERE new = 1;
(or whatever)
Run that every second, 5 seconds, 10 seconds, whatever seems reasonable based on your activity.
When count == N, run your process. When "time since last run" == 5 minutes, run your process.
The process is the same, you just check it more often with the two criteria.
This offers an advantage that you won't get rogue race condition where the job fires TWICE (because Job A found the insert count that just-so-happens to have been 5 minutes from when the last job ran). Rare, yes, but race conditions always seem to actively seek "rare" events that "never happen".
As for scheduling, a crontab is easy because you don't have to maintain your process, keep it alive, daemonize, etc. etc.
If you're already running in a long running container (app server, tomcat, etc.) then that problem is already solved and you can just leverage that.
Downside of cron is it's granularity, it only runs at most every minute. If that too long, it won't work for you. But if it's ok, then there's real value in having a simple process that just lights up, does it's check, and quits. Of course, it will have to persist it's state somehow (it could look in a job log to see when the last job ran, for example).
Within java, there are lots of options: raw threads, sleeping, Timers, ScheduledExecutorService, something like Quartz, EJB Timer beans (if you're running a Java EE container).
But, I'm a KISS fan. If a cron job can do it, let it, and do it once.
It is actually not that big using a ScheduledExecutorService:
private static final Runnable PROGRAM_RUNNABLE = new Runnable() {
#Override
public void run() {
// run the program
}
}
private ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
public static void main(String[] args) {
// database based
ses.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
boolean inserted = checkDatabase(); // check the insert in the db
if(inserted) {
PROGRAM_RUNNABLE.run();
}
}
}, 0, 1, TimeUnit.MINUTES);
// time based
ses.scheduleAtFixedRate(PROGRAM_RUNNABLE, 5, 5, TimeUnit.MINUTES);
}
A project requires the following scenario to happen:
class A has some objects(dynamically created) which it generates along with a time interval associated with each object. This class needs the generated object after this time interval only. I need to implement a mechanism which provides the class with the objects after it's associated time interval. It may also, sometime, need a particular object before the time interval expires.
Here's what I did:
Looked upon ConcurrentTaskExecutor and org.springframework.scheduling.concurrent but didn't find it useful because I don't want thousands of thread running each for an object. Also, I don't want to repeat a particular job after a time interval.
I created a Thread B which takes all the object in a queue, has an infinite loop which constantly checks all the object's time interval with the current time, and puts back if it's time interval has not expired.
while (true) {
timerObject = queue.take();
if (timerObject.getEndTime() < System.currentTimeMillis()) {
//Do something
} else {
queue.put(timerObject);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
This is not a very efficient implementation itself. It has a logical error associated with it. When the objects are very low in number(like 1 or 2), the objects are not in the queue and whenever I try to remove the object from the queue, it shows unsuccessful, because the while loop is having the object all the time. And hence I had to put a sleep to avoid that. I don't want to check each and every time interval when the queue size grows up to 10K or so.
Is there any simple and efficient way to achieve the solution. Any help appreciated.
You can use ConcurrentTaskScheduler, or implement something like it using DelayQueue.
You can use it with spring's Concurrent framework (for example subclassing ThreadPoolExecutorFactoryBean) or with core java Executors.
Currently I use while(true) and Thread.sleep() for checking for new records in the db and execute java code.
Here is an example:
public class StartCommands implements Runnable{
private Active_Job activeJob;
Runnable execute_command;
public StartCommands(){
activeJobs = new Active_Job();
}
#Override
public void run(){
int jobId = 0;
while(true){
//access the db and get one row from the table by the status
jobId = activeJobs.get(Status.NEW);
if (jobId > 0){
activeJob.updateStatus(Status.INIT);
execute_command = activeJob.getCommand();
new Thread(execute_command).start();
activeJob = new Active_Job();
jobId = 0;
}
Thread.sleep(10*1000);
}
}
}
I've few places in the code that I use this method. But I dont like the endless loop and check every 10 seconds for new row.
So what I'm looking for is some kind of listener: once new record has been entered - execute java code. Some of the inserts executed from the application and some are not.
The technique you are using is called polling. You are checking for new records, waiting a set amount of time, then checking again for new records. One good way to respond to new records might be to create a controller that handles inserting new records into the database and force all clients (who update database records) to use the controller to do so. Then the controller can alert you when there is a new record. To facilitate the controller's alerts, you can set up a web service where the controller can contact you.
I say that this "might" be a good way to do it because creating a controller and a web service is obviously extra work. However, it would make polling unnecessary. If you want to continue using your polling technique, you could make a service (producer) that does the polling and fills a queue with the new results. Your other program (consumer) can then retrieve items from the queue and do something with them.
There is no builtin "update listener" in MySQL (or any SQL database I'm aware of), so you have to build your own.
Notice that in your implementation, if two new rows are added you will handle one, wait 10 seconds, then handle the next one. Your code cannot handle more than one event every 10 seconds.
What you want to do is separate the polling of the database from the dispatching of the worker threads. Have the polling loop wake up every n seconds, read ALL new records from the database, and add them to a work queue. Have a consumer thread that is waiting on the queue and launches processors as messages appear on the queue. using a thread pool implementation.
#nir, Since there is no mysql database update listener in java so far, so what you can do is, create a database update trigger against the table, the change of which you want to listen. Within the trigger statement or code construct a function.Now from within that function call java function. Java function should be such that it modify some text, say "a". Now register the listener against the change in "a". And within the class implementing the text change listener of "a",put the code you want to execute.
The Condition Interface would work nicely for your needs. It will give you the granular control you are looking for, and it will avoid the problem of spinning the thread constantly.
http://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html
Use a trigger, call a User Defined Function that uses sys_exec() to run an external app that signals an inter-process semaphore. Your listener thread can wait on that and, when signaled, process the new records.
In oracle exists something called database change notification http://docs.oracle.com/cd/E11882_01/java.112/e16548/dbchgnf.htm and I just implement a component like yours is there something like that in mysql or what approach you arrived?
I'm using JDBC, need to constantly check the database against changing values.
What I have currently is an infinite loop running, inner loop iterating over a changing values, and each iteration checking against the database.
public void runInBG() { //this method called from another thread
while(true) {
while(els.hasElements()) {
Test el = (Test)els.next();
String sql = "SELECT * FROM Test WHERE id = '" + el.getId() + "'";
Record r = db.getTestRecord(sql);//this function makes connection, executeQuery etc...and return Record object with values
if(r != null) {
//do something
}
}
}
}
I'm think this isn't the best way.
The other way I'm thinking is the reverse, to keep iterating over the database.
UPDATE
Thank you for the feedback regarding timers, but I don't think it will solve my problem.
Once a change occurs in the database I need to process the results almost instantaneously against the changing values ("els" from the example code).
Even if the database does not change it still has to check constantly against the changing values.
UPDATE 2
OK, to anyone interested in the answer I believe I have the solution now. Basically the solution is NOT to use the database for this. Load in, update, add, etc... only whats needed from the database to memory.
That way you don't have to open and close the database constantly, you only deal with the database when you make a change to it, and reflect those changes back into memory and only deal with whatever is in memory at the time.
Sure this is more memory intensive but performance is absolute key here.
As to the periodic "timer" answers, I'm sorry but this is not right at all. Nobody has responded with a reason how the use of timers would solve this particular situation.
But thank you again for the feedback, it was still helpful nevertheless.
Another possibility would be using ScheduledThreadPoolExecutor.
You could implement a Runnable containing your logic and register it to the ScheduledExecutorService as follows:
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
executor.scheduleAtFixedRate(myRunnable, 0, 5, TimeUnit.SECONDS);
The code above, creates a ScheduledThreadPoolExecutor with 10 Threads in its pool, and would have a Runnable registered to it that will run in a 5 seconds period starting immediately.
To schedule your runnable you could use:
scheduleAtFixedRate
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
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.
And here you can see the advantages of ThreadPoolExecutor, in order to see if it fits to your requirements. I advise this question: Java Timer vs ExecutorService? too in order to make a good decision.
Keeping the while(true) in the runInBG() is a bad idea. You better remove that. Instead you can have a Scheduler/Timer(use Timer & TimerTask) which would call the runInBG() periodically and check for the updates in the DB.
u could use a timer--->
Timer timer = new Timer("runInBG");
//Taking an instance of class contains your repeated method.
MyClass t = new MyClass();
timer.schedule(t, 0, 2000);
As you said in the comment above, if application controls the updates and inserts then you can create a framework which notifies for 'BG' thread or process about change in database. Notification can be over network via JMS or intra VM using observer pattern or both local and remote notifications.
You can have generic notification message like (it can be class for local notification or text message for remote notifications)
<Notification>
<Type>update/insert</Type>
<Entity>
<Name>Account/Customer</Name>
<Id>id</Id>
<Entity>
</Notification>
To avoid a 'busy loop', I would try to use triggers. H2 also supports a DatabaseEventListener API, that way you wouldn't have to create a trigger for each table.
This may not always work, for example if you use a remote connection.
UPDATE 2
OK, to anyone interested in the answer I believe I have the solution now. Basically the solution is NOT to use the database for this. Load in, update, add, etc... only whats needed from the database to memory. That way you don't have to open and close the database constantly, you only deal with the database when you make a change to it, and reflect those changes back into memory and only deal with whatever is in memory at the time. Sure this is more memory intensive but performance is absolute key here.
I have an application that runs in JBoss. I have an incoming web service request that will update an ArrayList. I want to poll this list from another class every 60 seconds. What would be the most efficient way of doing this?
Could anyone point me to a good example?
I would also recommend ScheduledExecutorService, which offers increased flexibility over Timer and TimerTask including the ability to configure the service with multiple threads. This means that if a specific task takes a long time to run it will not prevent other tasks from commencing.
// Create a service with 3 threads.
ScheduledExecutorService execService = Executors.newScheduledThreadPool(3);
// Schedule a task to run every 5 seconds with no initial delay.
execService.scheduleAtFixedRate(new Runnable() {
public void run() {
System.err.println("Hello, World");
}
}, 0L, 5L, TimeUnit.SECONDS);
As abyx posted, Timer and TimerTask are a good lightweight solution to running a class at a certain interval. If you need a heavy duty scheduler, may I suggest Quartz. It is an enterprise level job scheduler. It can easily handle thousands of scheduled jobs. Like I said, this might be overkill for your situation though.
You can use Timer and TimerTask. An example is shown here.
See java.util.Timer. You'll need to start a robot in a separate thread when your app comes up and have it do the polling.
Check the answers to the question "How to run a task daily from Java" for a list of resources related to your problem.
The other answers are basically advising you do your own threads. Nothing wrong with that, but it isn't in conformance with the EJB spec. If that is a problem, you can use JBoss' timer facilities. Here is an example of how to do that.
However, if the EJB spec is at issue, storing state like an ArrayList isn't compliant as well, so if you are just reading some static variable anyway, specifically using a container Timer service is likely overkill.