Spring scheduler - getting time of next event - spring-boot

I've got a SpringBoot Scheduler that looks like this:
#Scheduled(cron = "*/10 * * * * * ") // Every 10 seconds
public void scheduleTaskUsingCronExpression() {
long now = System.currentTimeMillis() / 1000;
System.out.println("schedule tasks using cron jobs - " + now);
}
I'd like to get the time of the next event, so I can print it out at the end of each event. I've read about using CronExpression, which has a next() method, but not sure how I get the CronExpression. OR do I create a CronExpression and somehow pass it in instead of using the #Scheduled annotation?

I'm not sure I can get accurate interval time but I can get roughly correct next running time from following code.
#Value("${cron.schedule}") String schedule;
#Scheduled(cron = "${cron.schedule}") // Every 10 seconds
public void scheduleTaskUsingCronExpression() {
var expression = CronExpression.parse(schedule);
var result = expression.next(LocalDateTime.now());
System.out.println("schedule tasks using cron jobs - " + result);
}

You can define your cron string (that you use in the #Scheduled annotation) as a final field of your class, and then create CronExpression from it to find out the next trigger date.
Also, instead of using #Scheduled annotation, you can take a look at Spring's TaskScheduler (from the package org.springframework.scheduling). It has the method TaskScheduler#schedule with two arguments: a Runnable that will run in background and a CronTrigger to set the cron expression and and the timezone of executing background tasks.
UPD. One other way to reuse your cron is set it in your application.properties and use within #Value and #Scheduled annotations, e.g. #Scheduled(cron = ${property.from.file}). In this case you can also change the cron expression before running your application if needed.

Related

How to create Schedular on SpringBoot which invoke method

I have a table called JobSchedular
JobSchedular
JobCode
JobName
JobDescription
FunctionName
Status
RunInterval(CronEcpression)
Job001
Notify
To Send Notification
SendNotification
ACTIVE
0 * * * * ?
Job002
Appointment
To manage appointment
ManageAppointment
ACTIVE
0 * * * * ?
My Requirement is to Create Schedular on SPring Boot using #Scheduled annotation
which takes list of rows from tables and call the function dynamically based on corn expression
Now spring boot has built in support to quartz. Use this example to schedule job.
https://www.callicoder.com/spring-boot-quartz-scheduler-email-scheduling-example/

Spring Batch - Loop reader, processor and writer for N times

In Spring Batch, how to loop the reader,processor and writer for N times?
My requirement is:
I have "N" no of. customers/clients.
For each customer/client, I need to fetch the records from database (Reader), then I have to process (Processor) all records for the customer/client and then I have to write the records into a file (Writer).
How to loop the spring batch job for N times?
AFAIK I'm afraid there's no framework support for this scenario. Not at least the way you want to solve it.
I'd suggest to solve the problem differently:
Option 1
Read/Process/Write all records from all customers at once.You can only do this if they are all in the same DB. I would not recommend it otherwise, because you'll have to configure JTA/XA transactions and it's not worth the trouble.
Option 2
Run your job once for each client (best option in my opinion). Save necessary info of each client in different properties files (db data connections, values to filter records by client, whatever other data you may need specific to a client) and pass through a param to the job with the client it has to use. This way you can control which client is processed and when using bash files and/or cron. If you use Spring Boot + Spring Batch you can store the client configuration in profiles (application-clientX.properties) and run the process like:
$> java -Dspring.profiles.active="clientX" \
-jar "yourBatch-1.0.0-SNAPSHOT.jar" \
-next
Bonus - Option 3
If none of the abobe fits your needs or you insist in solving the problem they way you presented, then you can dynamically configure the job depending on parameters and creating one step for each client using JavaConf:
#Bean
public Job job(){
JobBuilder jb = jobBuilders.get("job");
for(Client c : clientsToProcess) {
jb.flow(buildStepByClient(c));
};
return jb.build();
}
Again, I strongly advise you not to go this way: ugly, against framework philosophy, hard to maintain, debug, you'll probably have to also use JTA/XA here, ...
I hope I've been of any help!
Local Partitioning will solve your problem.
In your partitioner, you will put all of your clients Ids in map as shown below ( just pseudo code ) ,
public class PartitionByClient implements Partitioner {
#Override
public Map<String, ExecutionContext> partition(int gridSize) {
Map<String, ExecutionContext> result = new HashMap<>();
int partitionNumber = 1;
for (String client: allClients) {
ExecutionContext value = new ExecutionContext();
value.putString("client", client);
result.put("Client [" + client+ "] : THREAD " + partitionNumber, value);
partitionNumber++;
}
}
return result;
}
}
This is just a pseudo code. You have to look to detailed documentation of partitioning.
You will have to mark your reader , processor and writer in #StepScope ( i.e. which ever part needs the value of your client ). Reader will use this client in WHERE clause of SQL. You will use #Value("#{stepExecutionContext[client]}") String client in reader etc definition to inject this value.
Now final piece , you will need a task executor and clients equal to concurrencyLimit will start in parallel provided you set this task executor in your master partitioner step configuration.
#Bean
public TaskExecutor taskExecutor() {
SimpleAsyncTaskExecutor simpleTaskExecutor = new SimpleAsyncTaskExecutor();
simpleTaskExecutor.setConcurrencyLimit(concurrencyLimit);
return simpleTaskExecutor;
}
concurrencyLimit will be 1 if you wish only one client running at a time.

Spring Boot schedules task from view

I want add and delete schedule tasks in runtime from views, is this possible? Maybe someone has an example code or good aticle about it?
Consider this approach. Instead of adding and deletion scheduled tasks, you may check every minute (or with another precision) actual moment against your views and run necessary tasks immediately. This will be easier. Check Quartz Scheduler, its CronExpression has isSatisfiedBy(Date date) method.
#Scheduled(cron = "5 * * * * *) // do not set seconds to zero, cause it may fit xx:yy:59
public void runTasks() {
LocalTime now = LocalTime.now(); // or Date now = new Date();
// check and run
}
I have met the same problem with you. Maybe, I can provide a not such good solution with the help of redis or database.
In the scheduled task, you can read a flag from redis, then you can decide if continue the task. For example
#Scheduled(cron = "....")
void myTask() {
Boolean flag = readFlagFromRedis(); // you can write the flag into redis or database to control the task
if (flag) {
// continue your task
}
}
then, you can control the tasks schedule in runtime.
Although I don't think this is a beautiful solution, it can meet your requirements

How to get the execution time(time to get response) of rest api in spring or using junit

I want to save the execution time of rest api. The is same as what we can see in postman next to status.
Is there any way in Junit?
Thanks in advance
You can do it manually.
example:
long time = System.currentTimeMillis();
Response response = server.newRequest("/requesturl").request().buildPost(Entity.text("45")).invoke();
long responseTime = (System.currentTimeMillis() - time);
save(responseTime);
Or if you want to test the response time then look here
The manual way is indeed pretty easy. Especially with Java 8 where you can do
private void timed(Runnable r) {
long time = System.currentTimeMillis();
r.run();
long responseTime = (System.currentTimeMillis() - time);
save(responseTime);
}
In JUnit you have the Stopwatch rule that allow you to have test execution calculated.
Codahale also have a #Timed annotation with a result that can be send to a collector. But there's a bit more wiring needed to make it all work.

JobExplorer.findRunningJobExecutions does not work correctly

In a project I use spring-batch, as a part of cleanup for processes that stuck I use
JobExplorer.findRunningJobExecutions(...)
but that function return empty set. After digging I found next problem: spring-batch use SQL like
SELECT E.JOB_EXECUTION_ID, ... from %PREFIX%JOB_EXECUTION E ... WHERE ... E.END_TIME is NULL .... After running long job, I got that from beginning 3 Dates in %PREFIX%JOB_EXECUTION (CREATE_TIME, START_TIME, END_TIME) have same value. This mean that SQL will always return empty set.
Question is, am I one who get this?
How to report bug to Spring team?
Here is the link to the Spring batch project home page
Jira's can be Entered here
Not sure what version you are running, but with version 2.1.1 (which is real old I know) but this code works.
jobOperator.getRunningExecutions(String jobName)
Here is the javadoc from that version
/**
* Get the id values of all the running {#link JobExecution JobExecutions}
* with the given job name.
*
* #param jobName the name of the job to search under
* #return the id values of the running {#link JobExecution} instances
* #throws NoSuchJobException if there are no {#link JobExecution
* JobExecutions} with that job name
*/
Set<Long> getRunningExecutions(String jobName) throws NoSuchJobException;
Link to the most update JobOperator
Hope this helps.

Resources