I have a web application, I need to run a backgroung process which will hit a web-service, after getting the response it will wait for few seconds(say 30) then again hit the service. The response data can vary from very less to very large, so i dont want to call the processagain untill i am finished with processing of data. So, its a recursive call with a time delay. How i intend to do is:
Add a ContextListener to web app.
On contextIntialized() method , call invokeWebService() i.e. arbitary method to hit web service.
invokeWebService will look like:
invokeWebService()
{
//make request
//hit service
//get response
//process response
timeDelayInSeconds(30);
//recursive call
invokeWebService();
}
Pls. suggest whether I am doing it right. Or go with threads or schedulers. Pls. answer with sample codes.
You could use a ScheduledExecutorService, which is part of the standard JDK since 1.5:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable r = new Runnable() {
#Override
public void run() {
invokeWebService();
}
};
scheduler.scheduleAtFixedRate(r, 0, 30, TimeUnit.SECONDS);
It is not recursive but repeated. You have two choice here:
Use a Timer and a TimerTask with scheduleAtFixedRate
Use Quartz with a repeated schedule.
In quartz, you can create a repeated schedule with this code:
TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(30))
.build()
From what I am getting, waiting sort of implies hanging, which I do not really think is a good idea. I would recommend you use something such as Quartz and run your method at whatever interval you wish.
Quartz is a full-featured, open source job scheduling service that can
be integrated with, or used along side virtually any Java EE or Java
SE application
Tutorials can be accessed here.
As stated in here you can do something like so:
JobDetail existingJobDetail = sched.getJobDetail(jobName, jobGroup);
if (existingJobDetail != null) {
List<JobExecutionContext> currentlyExecutingJobs = (List<JobExecutionContext>) sched.getCurrentlyExecutingJobs();
for (JobExecutionContext jec : currentlyExecutingJobs) {
if(existingJobDetail.equals(jec.getJobDetail())) {
//String message = jobName + " is already running.";
//log.info(message);
//throw new JobExecutionException(message,false);
}
}
//sched.deleteJob(jobName, jobGroup); if you want to delete the scheduled but not-currently-running job
}
Related
So I have a java app that calls 2 APIs.
Call an API to get a request a file to be generated
Call the second API to get the file.
The first API returns the credentials to get the file. The Second one returns the file but it may take a few seconds or minutes to be generated. What is the best way to account for the time delay between asking the file to be generated and the file being available to pull? Some retry logic should be necessary but on the initial call it always returns a 4xx HTTP response. What's the best way to make this api call maybe there's a better way than using RestTemplate to sequentially call the 2 apis? I thought of adding a short time delay before the 2nd call but I was wondering if there is a better library or async method I can use that's more efficient.
I'd appreciate any 2 cents thanks!
If the author of these two apis is a partner of yours, I think there's a better way, like, the file generator call a callback api of yours and then you call the second API to get the file. And as a supplement, considering unexpected exceptions during above process, a retry schedule to fetch the missed file is probably necessary.
But if you just want to implement the retry and async code more gracefully, the following is my idea
//call the first API
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
CompletableFuture<File> completionFuture = new CompletableFuture<>();
final ScheduledFuture<?> checkFuture = executor.scheduleAtFixedRate(() -> {
//Call the second API to get the file
//if("have got the file successfully") {
// completionFuture.complete(the file);
//} else {
// //do nothing
//}
}, 5, 1, TimeUnit.SECONDS);//set a reasonable schedule policy
completionFuture.whenComplete((file, thrown) -> {
//do something when the retry schedule complete
checkFuture.cancel(false);
});
completionFuture.orTimeout(10, TimeUnit.SECONDS);//setting a timeout policy is probably necessary
Like below link, is there java function that thread interrupt asynchronous queue and put in alertable?
https://learn.microsoft.com/en-us/windows/desktop/sync/using-a-waitable-timer-with-an-asynchronous-procedure-call
I want to make async timer function in java. I checked it works in c++. But I don't know if it is in java.
When main thread run and check periodically if there are the async timer fired and run it and going back and run again. That is what i want to do.
Of course, when checking async timer fired, I will use sleep with alertable.
I've tried to find it in google, but I didn't find.
Thanks in advance!
What I want to do more detail is below.
Let's assume that there is a program that getting requests like :
msg1 : msgname=aa1 to=sub1 waittime=1000 msgbody
msg2 : msgname=aa2 to=sub2 waittime=2000 msgbody
msg3 : msgname=aa3 to=sub1 waittime=3000 msgbody
msg4 : msgname=aa3 to=sub1 msgbody . .
and the program should pass each msg to sub1, sub2 described in msg's to field.
If waittime exists, it should pass the message as much as waittime millisec later. the program should do that in 1 thread, and there over 10 thousands msg in one second. If use just synchronous sleep, all msgs souldn't pass in a time and delayed. I check it works well in c++ code, and I have seen a commercial program made in java(maybe) does this. But I am novice in java and I want to know it is possible in java.
Java doesn't have concepts analogous to Windows' "alertable" and the APC queue, and I doubt that it would be possible to both use the Windows native APIs and integrate this with normal Java thread behavior.
The simple way to implement timers in Java is to use the standard Timer class; see the javadoc. If this isn't going to work for you, please explain your problem in more detail.
In response to your followup problem: yes it is possible in Java. In fact. there are probably many ways to do it. But Timer and TimerTask are a good a way as any. Something like this:
public class MyTask extends TimerTask {
private String msg;
private String to;
public Mytask(String msg, String to) {
this.msg = msg;
this.to = to;
}
public void run() {
// process message
}
}
Timer timer = new Timer();
while (...) {
// read message
timer.schedule(new MyTask(msg, to), waitTime);
}
I have an application that makes HTTP requests to a site, ant then retrives the responses, inspects them and if the contain specific keywords, writes both the HTTP request and response to an XML file. This application uses a spider to map out all the URLS of a site and then sends request(each URL in the sitemap is fed to a separate thread that sends the request). This way I wont be able to know when all the requests have been sent. At the end of all I request i want to convert the XML file to some other format. So in order to find out when the request have ended I use the following strategy :
I store the time of each request in a varible (when a new request is sent at a time later than the time in the variable, the varible is updated). Also I start a thread to monitor this time, and if the difference in the current time and the time in the varible is more than 1 min, I know that the sending of requests has ceased. I use the following code for this purpose :
class monitorReq implements Runnable{
Thread t;
monitorReq(){
t=new Thread(this);
t.start();
}
public void run(){
while((new Date().getTime()-last_request.getTime()<60000)){
try{
Thread.sleep(30000);//Sleep for 30 secs before checking again
}
catch(IOException e){
e.printStackTrace();
}
}
System.out.println("Last request happened 1 min ago at : "+last_request.toString());
//call method for conversion of file
}
}
Is this approach correct? Or is there a better way in which I can implement the same thing.
Your current approach is not reliable. You will get into race conditions - if the thread is updating the time & the other thread is reading it at the same time. Also it will be difficult to do the processing of requests in multiple threads. You are assuming that task finishes in 60 seconds..
The following are better approaches.
If you know the number of requests you are going to make before hand you can use a CountDownLatch
main() {
int noOfRequests = ..;
final CountDownLatch doneSignal = new CountDownLatch(noOfRequests);
// spawn threads or use an executor service to perform the downloads
for(int i = 0;i<noOfRequests;i++) {
new Thread(new Runnable() {
public void run() {
// perform the download
doneSignal.countDown();
}
}).start();
}
doneSignal.await(); // This will block till all threads are done.
}
If you don't know the number of requests before hand then you can use the executorService to perform the downloads / processing using a thread pool
main() {
ExecutorService executor = Executors.newCachedThreadPool();
while(moreRequests) {
executor.execute(new Runnable() {
public void run() {
// perform processing
}
});
}
// finished submitting all requests for processing. Wait for completion
executor.shutDown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.Seconds);
}
General notes:
classes in Java should start with Capital Letters
there seems to be no synchronization between your threads; access to last_request should probably be synchronized
Using System.currentTimeMillis() would save you some objects' creation overhead
swallowing an exception like this is not a good practice
Answer:
Your way of doing it is acceptable. There is not much busy waiting and the idea is as simple as it gets. Which is good.
I would consider changing the wait time to a lower value; there is so little data, that even doing this loop every second will not take too much processing power, and will certainly improve the rection time from you app.
I had a need to limit the connection rate (in my servlet) to certain external service and I decided to give ScheduledExecutorService a try. Scheduling itself seems to function just fine, but output gets printed only occasionally - in most cases nothing is outputted. Why does such happen? I'm using Tomcat 7 as a test server.
int waitingtimeinmilliseconds = 5000;
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture scheduledFuture = scheduledExecutorService.schedule() {
public void run() {
Fetcher fetcher = new Fetcher(loginname, password);
List<Item> items = fetcher.fetchItems();
// do something with the results
//ServletOutputStream
out.print("teststring" + items.size());
}
}, waitingtimeinmilliseconds, TimeUnit.MILLISECONDS);
scheduledExecutorService.shutdown();
You'll find very exhaustive description of what is causing your problem in: HttpServletResponse seems to periodically send prematurely (also check: starting a new thread in servlet).
Basically you cannot use external threads to write to servlet output. Once you leave doGet()/doPost(), servlet container assumes you are done and discards the output after flushing it to the client. But since you are writing to the stream asynchronously, sometimes the output gets through, while other times gets discarded.
If you want your rate limiting to be very scalable, consider async servlets (from 3.0). If you just want to throttle some clients, RateLimiter from guava will work for you1.
1 - see RateLimiter - discovering Google Guava on my blog.
This question already has an answer here:
Spawning threads in a JSF managed bean for scheduled tasks using a timer
(1 answer)
Closed 7 years ago.
I am developing a web application where I need to run a thread for 60 seconds which needs to check for response coming from a webservice. If the response arrives within 60 seconds I will forward to success othewise I will forward to a time out page after 60 seconds. I am using JSF 2.0?
I have thought of using the Timer but not sure whenther I can run the timer for sprcefic amount of time only.
Is there any smart solution for this ??
Yes, youre able to create a timer which expires after a certain amount of time. See this link http://docs.oracle.com/javaee/1.4/api/javax/ejb/TimerService.html.
Java < vers. 6
Create Session- or MessageDriven-Bean
Inject TimerService
#Ressource
TimerService ts;
Create Timer
...
// create Timer which starts after 10s every 10s
Timer timer = ts.createTimer(10000, 10000, "Test-Timer");
...
Important: Timer Interval has to be >7sec, see Java Specs
Create Method to be executed when timer fires
#Timeout //marks Method to be executed by Timer
public void timerFired(Timer timer) {
// your code here
}
Java > vers. 6
Much comfortable with the #Schedule-Annotation
#Schedule(second="*/45", minute="*", hour="*", persistent="false")
public void scheduler() {
// your code here
}
The above code implements a timer which gets fired every 45s of every minute of every hour.
Have a look at wikipedia for more information about cron syntax.
Both methods implement the Serializable-Interface, so they are both thread-safe.
if you would like to extend this rudimental functionality you should take a look at Quartz.
Hope this helped! Have Fun!
Do absolutely not use Timer for this! It's funny for one-time-run desktop applications, but it has severe potential problems when used in a lifetime long running Java EE web application.
Rather use the executors from the java.util.concurrent package. Here's a kickoff example:
ExecutorService executor = Executors.newSingleThreadExecutor(); // An application wide thread pool executor is better.
Callable<InputStream> task = new Callable<InputStream>() {
#Override
public InputStream call() throws Exception {
// Do here your webservice call job.
return new URL("http://stackoverflow.com").openStream();
}
};
try {
InputStream input = executor.invokeAny(Arrays.asList(task), 60, TimeUnit.SECONDS);
// Successful! Forward to success page here.
} catch (TimeoutException e) {
// Timeout occurred. Forward to timeout page here.
}
It sounds like you should just sit in a loop for 60 seconds and sleep for a second between checks. Once 60 seconds has passed or the request came in let the code continue and forward the user to the appropriate page.
This is the simplest way. You could also use an ajax polling system which would be more user friendly because you can update the user interface with a countdown.
long startTime = System.currentTimeMillis();
boolean success = false;
while (System.currentTimeMillis() < startTime + 60000) {
// do check
success = checkSucceeds();
if (success) break;
try {
Thread.sleep(1000);
} catch (InterruptedException interruptedException) {
// ignore
}
}
if (success)
// forward to success page
;
else
// forward to error page
;