I´m trying to build a method which creates scheduled jobs. These job call a URL.
public synchronized void scheduleNewJob(int jobNr, long newRate) throws NoSuchMethodException {
ScheduledFuture job = jobsMap.get(jobNr);
if (job != null) {// job was already scheduled, we have to cancel
// it
job.cancel(true);
}
// reschedule the same method with a new rate
final String methodName = "callApi";
Method method = new ApiCallerHelper().getClass().getMethod(methodName, String.class);
job = taskScheduler
.scheduleAtFixedRate(new ScheduledMethodRunnable(targetClass, method), newRate);
To do this I need to pass a URI param to my method (callApi).
Is there a possibility to do this? Or maybe a better way?
According to Spring documentation on ScheduledMethodRunnable:
...meant to be used for processing of no-arg scheduled methods.
I guess you can create a class wrapper with parametrized constructor. Wrap a class with the scheduled method in it. And the refer to param from scheduled method, while the method itself still would be no-arg and void-returning.
Related
I have some test code using Mockito:
public class ProcessFunctionClass {
public void processElement(Tuple2<String, String> tuple,
Context context, Collector<Tuple2<String, String>> collector) {
// if the state is empty, start a timer
if (listState.get().iterator().hasNext() == false)
context.timerService().registerEventTimeTimer(1000);
listState.add("someStringToBeStored");
// ...
}
}
I want to call the processElement() first, then verify that the timer (context.timerService()) was started, then call processElement() again, and then verify that the timer was NOT started again. I don't want to use verify() saying the method has been called once overall; I want to test for exactly what I described. How can I do that in Mockito?
Here is my attempt:
TimerService timerService = mock(TimerService.class);
processFunctionClass.processElement(tuple1, context, collector);
verify(timerService, times(1)).registerProcessingTimeTimer(anyLong()); // this passes as expected
processFunctionClass.processElement(tuple2, context, collector);
verify(timerService, times(0)).registerProcessingTimeTimer(anyLong()); // this fails as the method was called once before
The answer is to do the change, verify the method has been called, do the second change, and verify the method has been called once in total. Looks like this is the most accurate way of describing it that is available.
I am writing an integration test against some code that asynchronously creates a record when a different value is updated in the database. I would like to check the state of the system after the record is created, verifying that it was created as expected. The test therefore needs to wait until the record is created.
I can use Mockito to create a spy for the function that creates the record. Mockito even has the option to wait for the method to be called via Mockito.timeout, giving up if a certain amount of time has elapsed without the method being called:
// Use or create/wire in spy. In my case, this is set up with #SpyBean from spring-boot-test.
RecordCreationService recordCreationServiceSpy = ...;
testClass.update(someValue);
Mockito.verify(recordCreationServiceSpy, Mockito.timeout(10_000)).createRecord(ArgumentMatchers.any());
However, this merely waits for the call to have started, not for it to have been completed. Thus, this enters a race condition where the verification can finish before the desired call completes.
How can I cleanly and simply wait for the completion of a process before verifying in JUnit with Mockito?
This functionality doesn't directly exist in Mockito, as there is currently an open issue to add this functionality to Mockito (Mockito issue #1089).
The solution I am currently using is to write a custom answer for the spied method that waits for the call to be completed before returning. I then verify the result normally afterward.
#SpyBean
private RecordCreationService recordCreationServiceSpy;
#Test(timeout = 10_000)
public void recordShouldBeCreatedWhenDataIsUpdated() {
// Set up test here
updateValueAndWait(value);
assertEquals(1, recordRepository.findAll().size());
// Perform any additional verifications
}
private void updateValueAndWait(String value) {
CountDownLatch latch = new CountDownLatch(1);
Mockito.doAnswer(invocation -> {
Object result = invocation.callRealMethod();
latch.countDown();
return result;
}).when(recordCreationServiceSpy).insertRecord(any());
testClass.update(value);
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
I'm reading Quartz documentation and trying to understand can I pass inside Job instance method instead of class.
For example, in case with class I need to write:
public class MyJobClass implements Job {
public MyJobClass() {
// Instances of Job must have a public no-argument constructor.
}
public void execute(JobExecutionContext context)
throws JobExecutionException {
JobDataMap data = context.getMergedJobDataMap();
System.out.println("someProp = " + data.getString("someProp"));
}
}
And defining a Job Instance like:
JobDetail job1 = newJob(MyJobClass.class) // what about method here
.withIdentity("job1", "group1")
.usingJobData("someProp", "someValue")
.build();
By the same principle, I tried to define job instance passing method like:
// define the job
JobDetail job = newJob(testMethod())
.withIdentity("job1", "group1")
.build();
And method looks like:
private Class<? extends Job> testMethod() {
//...
return null;
}
But I get the error:
java.lang.IllegalArgumentException: Job class cannot be null.
Updated:
I return null in method, because if I don't do this I get:
Your testMethod() method returns null. Quartz does not accept null and fails.
Quartz wants to manage jobs by itself so it is why you are only allowed to pass class not instance.
Why do you need to provide your own instance? If you want to make it "persistent" to keep state between executions then Quartz provides stateful job concept, see http://www.quartz-scheduler.org/api/2.3.0/org/quartz/StatefulJob.html
I want to execute a specific method which contains a service call. As it includes a service call , it will take some time for execution. I want to add a timer which will keep program in wait till that method completes its executiuon. Any work around for this?
You can organize an asynchroneous method execution with a timeout with java.util.concurrent package
ExecutorService executorService = ...
Object res = executorService.submit(new Callable<Object>() {
public Object call() throws Exception {
... your logic
}
}).get(timeout, TimeUnit.MILLISECONDS);
You can use a separate thread to call that service and using join() method of Thread class, you can force main program to wait until that thread finishes the execution.
Sheduler
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand(){
#Override
public void execute() {
// code here
}
I'm trying to schedule a task depending on it's response. The task is something like:
public Date scheduledTask() {
Date nextRun;
// ...
nextRun = something();
// ...
return nextRun;
}
How can I make sure that the same task is called again when reaching the nextRun?
Thank you.
This is very simple with standard Quartz scheduler API. Inside your Job compute nextRun time and create a trigger with startAt() defined:
public class ScheduledJob implements Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
final Date nextRun = something();
Trigger trigger = newTrigger().
startAt(nextRun).
forJob(context.getJobDetail()).
build();
context.getScheduler().scheduleJob(trigger);
}
}
Tested, works like a charm.
Follow the ideas mentioned here, then you should be able to have:
public class GuaranteeSchedule implements Trigger {
private Future<?> resultForNextRun;
private TaskScheduler scheduler;
public void scheduledTask() {
// 'this' is this trigger that is used by the scheduler
// and the method `nextExecutionTime` is automatically called by the scheduler
resultForNextRun = scheduler.schedule(theTask, this);
// theTask is the object that calls something()
}
// Implementing Trigger to add control dynamic execution time of this trigger
#Override
public Date nextExecutionTime(TriggerContext tc) {
// make sure the result for the previous call is ready using the waiting feature of Future
Object result = resultForNextRun.get();
// Use tc or other stuff to calculate new schedule
return new Date();
}
}
The rest, you should follow the configuration mentioned in the reference. I believe this would resolve the problem of depending the next call of a trigger on the result of the previous. You may also need to be careful about the first call of scheduledTask to make sure resultForNextRun != null.