Reputation: 21
I have a use case where, I will insert a delivery and it's delivery time in database. Exact at the delivery time the delivery(which is a string) has to be printed to console. Any pointers how to achieve this?
Upvotes: 0
Views: 949
Reputation: 340040
ScheduledExecutorService
with java.timeThe Answer by user2880879 using ScheduledExecutorService
would be my chosen approach. But that Answer uses the terrible date-time classes Calendar
& Date
which were supplanted years ago by the modern java.time classes.
Instant now = Instant.now() ;
Retrieve delivery moment from database column of a data type akin to the SQL-standard type TIMESTAMP WITH TIME ZONE
. JDBC 4.2 requires support for OffsetDateTime
.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Check that you got a non-null value.
Objects.requireNonNull( odt ) ; // Throws exception if null.
Check that your retrieved moment is in the future.
if( ! odt.toInstant().isAfter( now ) ) { … handle error }
Tip: You might also want to be sure the future delivery time as at least a certain amount of time in the future, time enough for this code to run and the executor service to execute.
Extract an Instant
from that OffsetDateTime
.
Instant then = odt.toInstant() ;
Calculate elapsed time as a Duration
.
Duration duration = Duration.between( now , then ) ;
Define a task, as a Runnable
or Callable
.
Runnable runnable = () -> {
System.out.println( "Delivery made at: " + Instant.now() ) ;
};
Somewhere earlier in your app you would have instantiated a ScheduledExecutorService
, and kept a reference. Using the Executors
utility class is the usual way to get an executor service.
For this purpose, we likely want a single-threaded service. You can optionally create a service backed by a pool of multiple threads.
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor() ;
Schedule our task to run after our duration of time elapses.
ses.schedule( runnable , duration.toSeconds() , TimeUnit.SECONDS ) ;
Tips:
Runnable
with a try-catch. Any exception bubbling up will silently prevent any more tasks scheduled on that executor service from ever executing. If using a Jakarta compliant server supporting the Jakarta Concurrency specification, then this work is even easier. That spec relieves you of the chore of starting, managing, and shutting down your executor service.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Upvotes: 1
Reputation: 1430
Assume a microservices who has more than one instance responsible for print delivery at delivery time and you want only one instance work at the same time:
First method
The answer from @Jalil.Jarjanazy is can help you.code may be like this:
define job:
public class PrintDeliveryJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// print job
}
}
define save delivery method:
public void saveDelivery(String deliveryName, Date deliveryDate) throws Exception {
saveDeliveryToDataBase(deliveryName, deliveryDate);
JobDetail jobDetail = JobBuilder.newJob()
.ofType(PrintDeliveryJob.class)
.storeDurably().withIdentity(JobKey.jobKey(deliveryName))
.withDescription("Invoke " + deliveryName + " Job service...").build();
// you need to calculate the expression,it may be a hard work
CronExpression cronExpression = null;
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey(deliveryName))
.withDescription(deliveryName + " trigger")
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionFireAndProceed()
.inTimeZone(TimeZone.getDefault()))
.forJob(jobDetail)
.build();
scheduler.scheduleJob(jobDetail, trigger);
}
public void saveDeliveryToDataBase(String deliveryName, Date deliveryDate) {
// save to your data base like mysql、mongodb or other data base
}
Second method
1、define a job who get data from data base and check if need to print delivery or not.
2、use quartz define a schedule task execute the job one times per second.
Upvotes: 0
Reputation: 297
Or you can use JDK's ScheduledExecutorService
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Calendar futureTime = Calendar.getInstance();
//Here set time when you want to perform logic , display message etc.
futureTime.add(Calendar.SECOND, 5);
Date now = new Date();
long runafter = now.getTime() - futureTime.getTime().getTime();
// Within this you can write logic to perform action on that future time
Runnable runnable = () -> System.out.println("Hello, execute your logic here");
//This is one of schedule , will execute your logic defined in Runnable
scheduler.schedule(runnable, runafter, MICROSECONDS);
Upvotes: 0