I am running a scheduled task in the web application using the java SingleThreadScheduledExecutor
The problem I have is - How do I identify whether the scheduler is still running and has not crashed?
Is there a better way of doing it rather than having another scheduler to check this particular scheduler
there is actually a way to check
public class TaskSchedulerService{
private final ThreadPoolTaskScheduler taskScheduler; //initialize it here or in constructor
private Map<String,ScheduledFuture<?>> scheduleMap = new ConcurrentHashMap<>();
public TaskSchedulerServiceImpl() {
this.schedulerName = schedulerName;
taskScheduler.initialize();
}
public boolean isScheduled(String taskId) {
final ScheduledFuture<?> exits = scheduledTasks.get(taskId);
return exits != null && exits.isDone();
}
public ScheduledFuture<?> schedule(String taskId, Runnable task, Date date) {
ScheduledFuture<?> scheduled = scheduleMap.get(taskId);
if (scheduled==null ) {
ScheduledFuture<?> future = taskScheduler.schedule(task, date);
scheduleMap.put(taskId, future);
return future;
} else {
// log it is already scheduled
return scheduled;
}
}
i know it is too late but i hope others can get benefit from it
The logic behind the implementation is whenever you are trying to schedule a task, you will have to add it to the map with the taskId as well, in this case it is better to find any task if exists in MAP or if needed remove it as well as checking if that task is done or not
The answer depends on what your scheduler does really. For instance, you can produce a file or update a field in a db or such thing that can be checked and the time interval (from now to last update) can be calculated. In your case, if the time interval of file creation or db updated is more than half an hour this means the job did stop. But notice that scheduled jobs are meant to last forever like love.
Related
I have an implementation like this which doesn't work. As you see, job takes ~5sec and should run on fixedRate 1sec. That means there should be ~5jobs running in parallel but Spring wait to finish a job before starts another one...
If I add second #Scheduled job 'schedule2' with the same and parameters, I have 2 different jobs running in parallel but never the same job. Is it somehow possible to achieve this?
#Scheduled(fixedRate = 1000)
private void schedule1() {
int index = atomicInteger1.addAndGet(1);
logger.info("Run Schedule1 nr.{} started at: {}", index, LocalDateTime.now());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
logger.info("Schedule1 nr.{} finished at: {}", index, LocalDateTime.now());
}
}
#Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
Each scheduled task will never run in parallel in this case. That's because the task takes longer than the given fixedRate. Why? Because ScheduledExecutorService#scheduleAtFixedRate is called, and as the documentation says (bolded is mine):
... If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
One way of solving this is by using #Async and #EnableAsync. Many examples are available in the Spring docs:
#EnableAsync
public class Example {
#Async
#Scheduled(fixedRate = 1000)
public void schedule1() throws InterruptedException {
Thread.sleep(5000);
}
}
If you really want to achieve what you want, you should manage the threads by your own, calling to a service from the job in a separate thread.. but I don't see a reason to do that at least you're only testing and playing with Jobs at home for pet projects.
Anyway, have a look at this:
https://www.baeldung.com/java-future
In the system, I have an object - let's call it TaskProcessor. It holds queue of tasks, which are executed by some pool of threads (ExecutorService + PriorityBlockingQueue)
The result of each task is saved in the database under some unique identifier.
The user, who knows this unique identifier, may check the result of this task. The result could be in the database, but also the task could still wait in the queue for execution. In that case, UserThread should wait until the task will be finished.
Additionally, the following assumptions are valid:
Someone else could enqueue the task to TaskProcessor and some random UserThread can access the result if he knows the unique identifier.
UserThread and TaskProcess are in the same app. TaskProcessor contains a pool of threads, and UserThread is simply servlet Thread.
UserThread should be blocked when asking for the result, and the result is not completed yet. UserThread should be unblocked immediately after TaskProcessor complete task (or tasks) grouped by a unique identifier
My first attempt (the naive one), was to check the result in the loop and sleep for some time:
// UserThread
while(!checkResultIsInDatabase(uniqueIdentifier))
sleep(someTime)
But I don't like it. First of all, I am wasting database connections. Moreover, if the task would be finished right after sleep, then the user will wait even if the result just appeared.
Next attempt was based on wait/notify:
//UserThread
while (!checkResultIsInDatabase())
taskProcessor.wait()
//TaskProcessor
... some complicated calculations
this.notifyAll()
But I don't like it either. If more UserThreads will use TaskProcessor, then they will be wakened up unnecessarily every time some task would be completed and moreover - they will make unnecessary database calls.
The last attempt was based on something which I called waitingRoom:
//UserThread
Object mutex = new Object();
taskProcessor.addToWaitingRoom(uniqueIdentifier, mutex)
while (!checkResultIsInDatabase())
mutex.wait()
//TaskProcessor
... Some complicated calculations
if (uniqueIdentifierExistInWaitingRoom(taskUniqueIdentifier))
getMutexFromWaitingRoom(taskUniqueIdentifier).notify()
But it seems to be not secure. Between database check and wait(), the task could be completed (notify() wouldn't be effective because UserThread didn't invoke wait() yet), which may end up with deadlock.
It seems, that I should synchronize it somewhere. But I am afraid that it will be not effective.
Is there a way to correct any of my attempts, to make them secure and effective? Or maybe there is some other, better way to do this?
You seem to be looking for some sort of future / promise abstraction. Take a look at CompletableFuture, available since Java 8.
CompletableFuture<Void> future = CompletableFuture.runAsync(db::yourExpensiveOperation, executor);
// best approach: attach some callback to run when the future is complete, and handle any errors
future.thenRun(this::onSuccess)
.exceptionally(ex -> logger.error("err", ex));
// if you really need the current thread to block, waiting for the async result:
future.join(); // blocking! returns the result when complete or throws a CompletionException on error
You can also return a (meaningful) value from your async operation and pass the result to the callback. To make use of this, take a look at supplyAsync(), thenAccept(), thenApply(), whenComplete() and the like.
You can also combine multiple futures into one and a lot more.
I believe replacing of mutex with CountDownLatch in waitingRoom approach prevents deadlock.
CountDownLatch latch = new CountDownLatch(1)
taskProcessor.addToWaitingRoom(uniqueIdentifier, latch)
while (!checkResultIsInDatabase())
// consider timed version
latch.await()
//TaskProcessor
... Some complicated calculations
if (uniqueIdentifierExistInWaitingRoom(taskUniqueIdentifier))
getLatchFromWaitingRoom(taskUniqueIdentifier).countDown()
With CompletableFuture and a ConcurrentHashMap you can achieve it:
/* Server class, i.e. your TaskProcessor */
// Map of queued tasks (either pending or ongoing)
private static final ConcurrentHashMap<String, CompletableFuture<YourTaskResult>> tasks = new ConcurrentHashMap<>();
// Launch method. By default, CompletableFuture uses ForkJoinPool which implicitly enqueues tasks.
private CompletableFuture<YourTaskResult> launchTask(final String taskId) {
return tasks.computeIfAbsent(taskId, v -> CompletableFuture // return ongoing task if any, or launch a new one
.supplyAsync(() ->
doYourThing(taskId)) // get from DB or calculate or whatever
.whenCompleteAsync((integer, throwable) -> {
if (throwable != null) {
log.error("Failed task: {}", taskId, throwable);
}
tasks.remove(taskId);
})
);
/* Client class, i.e. your UserThread */
// Usage
YourTaskResult taskResult = taskProcessor.launchTask(taskId).get(); // block until we get a result
Any time a user asks for the result of a taskId, they will either:
enqueue a new task if they are the first to ask for this taskId; or
get the result of the ongoing task with id taskId, if someone else enqueued it first.
This is production code currently used by hundreds of users concurrently.
In our app, users ask for any given file, via a REST endpoint (every user on its own thread). Our taskIds are filenames, and our doYourThing(taskId) retrieves the file from the local filesystem or downloads it from an S3 bucket if it doesn't exist.
Obviously we don't want to download the same file more than once. With this solution I implemented, any number of users can ask for the same file at the same or different times, and the file will be downloaded exactly once. All users that asked for it while it was downloading will get it at the same time the moment it finishes downloading; all users that ask for it later, will get it instantly from the local filesystem.
Works like a charm.
What I understood from the question details is-
When UserThread requests for result, there are 3 possibilities:
Task has been already completed so no blocking of user thread and directly get result from DB.
Task is in queue or executing but not yet completed, so block the user thread(till now there should not be any db queries) and just after completion of task(the task result must be saved in DB at this point), unblock user thread(now user thread can query the DB for result)
There is no task submitted ever for the given uniqueIdentifier which user has requested, in this case there will be empty result from db.
For point 1 and 3, Its straight forward, there will not be any blocking of UserThread, just query the result from DB.
For point 2 - I have written a simple implementation of TaskProcessor. Here I have used ConcurrentHashMap to keep the current tasks which are not yet completed. This map contains the mapping between UniqueIdentifier and corresponding task. I have used computeIfPresent() (introduced in JAVA - 1.8) method of ConcurrentHashMap which guarantees that the invocation of this method is thread safe for the same key. Below is what java doc says:
Link
If the value for the specified key is present, attempts to compute a
new mapping given the key and its current mapped value. The entire
method invocation is performed atomically. Some attempted update
operations on this map by other threads may be blocked while
computation is in progress, so the computation should be short and
simple, and must not attempt to update any other mappings of this map.
So with use of this method, whenever there is a user thread request for a task T1 and if the task T1 is in queue or executing but not completed yet, then user thread will wait on that task.
When the task T1 will be completed, all the user requests thread which were waiting on task T1 will be notified and then we will remove task T1 from the above map.
Other classes reference used in below code are present on this link.
TaskProcessor.java:
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
public class TaskProcessor implements ITaskProcessor {
//This map will contain all the tasks which are in queue and not yet completed
//If there is scenario where there may be multiple tasks corresponding to same uniqueIdentifier, in that case below map can be modified accordingly to have the list of corresponding tasks which are not completed yet
private final Map<String, Task> taskInProgresssByUniqueIdentifierMap = new ConcurrentHashMap<>();
private final int QUEUE_SIZE = 100;
private final BlockingQueue<Task> taskQueue = new ArrayBlockingQueue<Task>(QUEUE_SIZE);
private final TaskRunner taskRunner = new TaskRunner();
private Executor executor;
private AtomicBoolean isStarted;
private final DBManager dbManager = new DBManager();
#Override
public void start() {
executor = Executors.newCachedThreadPool();
while(isStarted.get()) {
try {
Task task = taskQueue.take();
executeTaskInSeperateThread(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void executeTaskInSeperateThread(Task task) {
executor.execute(() -> {
taskRunner.execute(task, new ITaskProgressListener() {
#Override
public void onTaskCompletion(TaskResult taskResult) {
task.setCompleted(true);
//TODO: we can also propagate the taskResult to waiting users, Implement it if it is required.
notifyAllWaitingUsers(task);
}
#Override
public void onTaskFailure(Exception e) {
notifyAllWaitingUsers(task);
}
});
});
}
private void notifyAllWaitingUsers(Task task) {
taskInProgresssByUniqueIdentifierMap.computeIfPresent(task.getUniqueIdentifier(), new BiFunction<String, Task, Task>() {
#Override
public Task apply(String s, Task task) {
synchronized (task) {
task.notifyAll();
}
return null;
}
});
}
//User thread
#Override
public ITaskResult getTaskResult(String uniqueIdentifier) {
TaskResult result = null;
Task task = taskInProgresssByUniqueIdentifierMap.computeIfPresent(uniqueIdentifier, new BiFunction<String, Task, Task>() {
#Override
public Task apply(String s, Task task) {
synchronized (task) {
try {
//
task.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return task;
}
});
//If task is null, it means the task was not there in queue, so we direcltly query the db for the task result
if(task != null && !task.isCompleted()) {
return null; // Handle this condition gracefully, If task is not completed, it means there was some exception
}
ITaskResult taskResult = getResultFromDB(uniqueIdentifier); // At this point the result must be already saved in DB if the corresponding task has been processed ever.
return taskResult;
}
private ITaskResult getResultFromDB(String uniqueIdentifier) {
return dbManager.getTaskResult(uniqueIdentifier);
}
//Other thread
#Override
public void enqueueTask(Task task) {
if(isStarted.get()) {
taskInProgresssByUniqueIdentifierMap.putIfAbsent(task.getUniqueIdentifier(), task);
taskQueue.offer(task);
}
}
#Override
public void stop() {
isStarted.compareAndSet(true, false);
}
}
Let me know in comments if you have any queries.
Thanks.
I'm trying to solve a problem similar to downloading new mails from mail servers by mail client. I have a task, which is performed regularly (next iteration is 10 minutes after the last one ends for example) but there is also a possibility to run the task manually.
When I am trying to run the job manually and job is not running at this moment (is appointed for later), I cancel the appointment and schedule it for now. When the job is already running I do not cancel it, but wait until it finishes and run it again. But only one task can wait this way.
My problem is that I do not know how to synchronize the jobs to make it thread safe and make sure that job never runs twice at the same time.
To make it more clear. The main problem is that simple asking if the job is running and deciding based on what I get is not enough, because between the question and action the situation can change. It is a short span but the probability is not zero. And the same problem is with deciding if I should run the job again at the end of his run. If my decision is based on the value of some variable or some other if clause, then between testing its value and performing some action, some other thread can change it and I can end up with two scheduled jobs or none at all.
Have you considered using a DelayQueue?
To make your job run now you just need to persuade it to return 0 form getDelay(TimeUnit unit).
The main way to do that check you are telling about is to check, to lock and after that to repeat the same check:
public class OneQueuedThread extends Thread {
static int numberRunning =0;
public void run() {
if (numberRunning<2) {
synchronized (OneQueuedThread.class){
if (numberRunning<2) {
numberRunning++;
// ---------------your process runs here
numberRunning--;
}
}
}
}
}
So, only one attempt to run the thread while it is already running will wait until the end of the running thread and start after it.
As for scheduling, let's use the TimerTask features:
public class ScheduledTask extends TimerTask {
ScheduledTask instance;
/**
* this constructor is to be used for manual launching
*/
public void ScheduledTask(){
if (instance == null){
instance = this;
} else {
instance.cancel();
}
instance.run();
}
/**
* This constructor is to be used for scheduled launching
* #param deltaTime
*/
public ScheduledTask(long deltaTime){
instance = this;
Timer timer = new Timer();
timer.schedule(instance, deltaTime);
}
public void run() {
OneQueuedThread currentTread;
currentTread = new OneQueuedThread();
currentTread.start();
}
}
I use a Timer and TimerTasks to schedule some tasks to be execuded. Some of the tasks must be rescheduled. I need a mechanism to “name” tasks (e.g. by a String ID) so I can reschedule them or remove them and schedule them at a new time.
The project that I’m working on is a Flight Display System. Every flight when inserted to the DB has a scheduled arrival and departure time. So I use one timer task to update airport displays when a flight must be shown and another one to hide it.
Everything is fine until there is a change in the flight time. The user updates the time in the DB but then I need to reschedule the display update times. This is the point where I need your help.
What do you think about a simple HashMap<UUID, TimerTask> tasks. You could find any Task by the given ID, cancel it, or reschedule it later.
update
public class TimerThingy{
HashMap<UUID,TimerTask> tasks = new HashMap<UUID,TimerTask>();
Timer timer = new Timer();
public UUID createAndStartTimer(final Runnable task, Date when){
TimerTask timerTask = new TimerTask(){
public void run(){
task.run();
}
}
timer.schedule(TimerTask timerTask, Date when);
UUID id = UUID.randomUUID();
tasks.put(id, t);
return id;
}
public void cancelTimer(UUID id){
tasks.get(id).cancel();
}
}
Well this is some kind of easiest Scheduler with an ID to cancel. I think you may use something else as ID, because you may to find the correct Task to cancel. But thats up to you..
//You can create a map where you store your tasks, indexed by the id.
Map<String,TimerTask> tasks = new HashMap<String,TimerTask>();
You uses a function to generate your named tasks:
public TimerTask createTask(String name, final Runnable r){
TimerTask task = new TimerTask(){
public void run(){
r.run();
}
}
//here, you save it to the HashMap
tasks.put(name, task);
return task;
}
// update airport displays when a flight must be shown and another to hide it.
Now, to create a task, you create the runnable, like you used to, and creates the name you'd want it to have, for example fligthnumer-show, or flightnumer-hide, and then call that function to create the task.
Runnable r= ... //whatever you does here
String name = "1234-show";
TimerTask task = createTask( name, r);
Now, you can schedule the task,or do whatever you need. besides, your task is saved, so, if you need it again, to cancel it, or to schedule it again, you just need to retrieve it from the hashmap, calling it for its name:
TimerTask task = tasks.get("1234-show");
In this example, it is not really useful, but in your real application, if you are, for instance, creating task dinamically, is easy to build a dynamic list of tasks. Say you have to schedule a task to show the info or a new flight, that probably you already did the day before, or probably is a new one. You can check if there is a task already, and if it is, you can use it, otherwise you crete it and save it.
//say you have flight number in a var called flightNumber, and you are building a "show" task
String name= flightNumber+"show";
TimerTask task = tasks.get(name); //if the task is found, you can use it
//instead, f there is not such task, null will be returned, in that case, you create it.
if (null== task) {
//do al the required stuff, like get the runnable ready, and create the task
task = createTask( name, r);
}
//so here, you can do whatever you need with the task
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();