This is what I have in my Servlet.
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("Initializing...");
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.execute(new Runnable() {
public void run() {
System.out.println("Inside Thread!!!");
for(int i=1; i<5; i++){
System.out.println("Date: " + new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
executorService.shutdown();
// Some more piece of code is there
}
What I am doing here:
I have created a separate thread where the date gets printed after 5 sec in the console.
What I want to do:
When I run this code, I get this output printed in the console:
Initializing...
Inside Thread!!!
Date : Sat Nov 01 15:57:57 GMT 2014
Date : Sat Nov 01 15:58:02 GMT 2014
Date : Sat Nov 01 15:58:07 GMT 2014
Date : Sat Nov 01 15:58:12 GMT 2014
I want the same set of messages to be printed in a jsp page in such a way that the Date gets printed in an interval of 5 sec (by sending multiple response to the browser whenever a Syetem.out.println() method is executed int he above code).
Reason for pushing message from server:
In the above example, I am printing simple messages in a loop. But in real scenario, there are some calculations, hence the messages will be available at different time frames (i.e. not after every 5 sec, some messages will be available in quick time while the other messages might take some more time). Hence if I push from the server, then I can push the messages whenever it is available.
Unable to understand:
I am not sure how to send multiple response to the browser from a separate thread (i.e. from ExecutorService in the above code). I was looking into the setInterval method present in javascript but am not sue how to frame this code using it.
I am free to use jQuery or javascript to get this work. Please advise.
Instead of trying to push from the server, you should have the client make an AJAX request every five seconds, and you should return the snippet that you want printed from that endpoint.
Related
I need to obtain the master public DNS value via the Java SDK. The only information that I'll have at the start of the application is the ClusterName which is static.
Thus far I've been able to pull out all the other information that I need excluding this and this, unfortunately is vital for the application to be a success.
This is the code that I'm currently working with:
List<ClusterSummary> summaries = clusters.getClusters();
for (ClusterSummary cs: summaries) {
if (cs.getName().equals("test") && WHITELIST.contains(cs.getStatus().getState())) {
ListInstancesResult instances = emr.listInstances(new ListInstancesRequest().withClusterId(cs.getId()));
clusterHostName = instances.getInstances().get(0).toString();
jobFlowId = cs.getId();
}
}
I've removed the get for PublicIpAddress as wanted the full toString for testing. I should be clear in that this method does give me the DNS that I need but I have no way of differentiating between them.
If my EMR has 4 machines, I don't know which position in the list that Instance will be. For my basic trial I've only got two machines, 1 master and a worker. .get(0) has returned both the values for master and the worker on successive runs.
The information that I'm able to obtain from these is below - my only option that I can see at the moment is to use the 'ReadyDateTime' as an identifier as the master 'should' always be ready first, but this feels hacky and I was hoping on a cleaner solution.
{Id: id,
Ec2InstanceId: id,
PublicDnsName: ec2-54--143.compute-1.amazonaws.com,
PublicIpAddress: 54..143,
PrivateDnsName: ip-10--158.ec2.internal,
PrivateIpAddress: 10..158,
Status: {State: RUNNING,StateChangeReason: {},
Timeline: {CreationDateTime: Tue Feb 21 09:18:08 GMT 2017,
ReadyDateTime: Tue Feb 21 09:25:11 GMT 2017,}},
InstanceGroupId: id,
EbsVolumes: []}
{Id: id,
Ec2InstanceId: id,
PublicDnsName: ec2-54--33.compute-1.amazonaws.com,
PublicIpAddress: 54..33,
PrivateDnsName: ip-10--95.ec2.internal,
PrivateIpAddress: 10..95,
Status: {State: RUNNING,StateChangeReason: {},
Timeline: {CreationDateTime: Tue Feb 21 09:18:08 GMT 2017,
ReadyDateTime: Tue Feb 21 09:22:48 GMT 2017,}},
InstanceGroupId: id
EbsVolumes: []}
Don't use ListInstances. Instead, use DescribeCluster, which returns as one of the fields MasterPublicDnsName.
To expand on what was mentioned by Jonathon:
AmazonEC2Client ec2 = new AmazonEC2Client(cred);
DescribeInstancesResult describeInstancesResult = ec2.describeInstances(new DescribeInstancesRequest().withInstanceIds(clusterInstanceIds));
List<Reservation> reservations = describeInstancesResult.getReservations();
for (Reservation res : reservations) {
for (GroupIdentifier group : res.getGroups()) {
if (group.getGroupName().equals("ElasticMapReduce-master")) { // yaaaaaaaaah, Wahay!
masterDNS = res.getInstances().get(0).getPublicDnsName();
}
}
}
AWSCredentials credentials_profile = null;
credentials_profile = new
DefaultAWSCredentialsProviderChain().getCredentials();
AmazonElasticMapReduceClient emr = new
AmazonElasticMapReduceClient(credentials_profile);
Region euWest1 = Region.getRegion(Regions.US_EAST_1);
emr.setRegion(euWest1);
DescribeClusterFunction fun = new DescribeClusterFunction(emr);
DescribeClusterResult res = fun.apply(new
DescribeClusterRequest().withClusterId(clusterId));
String publicDNSName =res.getCluster().getMasterPublicDnsName();
Below is the working code to get the public DNS name.
We have a problem. Our customers are complaining that they are getting duplicate emails in their in-box. Some days up to 5 or 6 instances of the exact same email at the exact same time. We don't understand why. The code has been re-written at least once but the problem persists.
I'll try to explain this... but it's a bit complicated :O(
Every night (early morning) we want to send our users a daily report containing usage stats. So we have a cron job:
<cron>
<url>/redacted/report/url</url>
<description>Send out daily reports to active subscribers</description>
<schedule>every 2 hours</schedule>
</cron>
The cron job hits the servlet get method:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AccountFilter filter = AccountFilter.forWebSafeName(req.getParameter("filter"));
createTasks(filter, null);
}
Which calls the createTasks method with a null cursor:
private void createTasks(AccountFilter accountFilter, String cursor) {
try {
PagedResults<Account> pagedAccounts = accountRepository.getAccounts(accountFilter.getFilter(), 50, cursor);
createTaskBatch(pagedAccounts);
// If there are still more results in cursor, then send cursor back to this servlet's doPost method so we don't hit the request time limit
if (pagedAccounts.getCursor() != null) {
getQueue(QUEUE_NAME).add(withUrl(WORKER_URL).param(CURSOR_KEY, pagedAccounts.getCursor()).param(FILTER_KEY, accountFilter.getWebSafeName()));
}
} catch(Exception ex) {
logger.log(Level.WARNING, "Problem creating daily report task batch for filter " + accountFilter.getWebSafeName(), ex);
}
}
which grabs 50 accounts and iterates over them creating new queued jobs for the emails that should be sent at this time. There is code to explcitely check the last report sent timestamp and update the timestamp BEFORE creating the new queued task. This should err on the side of not sending the report rather than sending duplicates:
private void createTaskBatch(PagedResults<Account> pagedAccounts) {
// GAE datastore query might return duplicate results?!
List<Account> list = pagedAccounts.getResults();
Set<Account> noDuplicates = new HashSet<>(list);
int dups = list.size() - noDuplicates.size();
if ( dups > 0 ){
logger.warning ("Accounts paged results contained " + dups + " duplicates!");
}
for (Account account : noDuplicates) {
try {
if (lastReportSentOver12HoursAgo(account)) {
List<Parent> parents = parentRepository.getVerifiedParentsForAccount(account.getId());
if (eitherParentSubscribed(parents)) {
List<AccountUser> users = accountUserRepository.listUsers(account.getId());
List<Device> devices = getUserDevices(account, users);
if (!devices.isEmpty()) {
DateTimeZone tz = getMostCommonTimezone(devices);
if ( null == tz ){
logger.warning("No timezone found for account: " + account.getId() );
}
else{
// Send early in the morning as the report contains the previous day's stats
if (now(tz).getHourOfDay() < 7) {
// mark sent now because queue might not be processed for a while
// and the next cursor set might contain some of the same accounts
accountRepository.markReportSent(account.getId(), now());
getQueue(QUEUE_NAME).add(withUrl(DailyReportServlet.WORKER_URL).param(DailyReportServlet.ACCOUNT_ID, account.getId()).param(DailyReportServlet.COMMON_TIMEZONE, tz.getID()));
}
}
}
}
}
} catch(Exception ex) {
logger.log(Level.WARNING, "Problem creating daily report task for " + account.getId(), ex);
}
}
}
The servlet POST method takes care of handling the follow up pages of results via the cursor method:
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
AccountFilter accountFilter = AccountFilter.forWebSafeName(req.getParameter(FILTER_KEY));
logger.log(Level.INFO, "doPost hit from task queue with filter " + accountFilter.getWebSafeName());
String cursor = req.getParameter(CURSOR_KEY);
createTasks(accountFilter, cursor);
}
There is another servlet that handles each report task and it just creates the email contents and calls send on the com.sendgrid.SendGrid class.
The eventual consistency in Datastore seems a likely candidate but that should be resolved within a few seconds and I don't see how that would account for both the number of customers complaining and the number of duplicates that some customers see.
Help! Any ideas? Are we being dumb somewhere?
UPDATED
For clarity... the email send task queue ends up in this method which does catch exceptions and reports them back to us. We don't see an exception for the duplicate cases:
private void sendReport(Account account, DateTimeZone tz) throws IOException, EntityNotFoundException {
try {
boolean sent = false;
Map<String, Object> root = buildEmailData(account, tz);
for (Parent parent : parentRepository.getVerifiedParentsForAccount(account.getId())) {
if (parent.getEmailPreferences().isSubscribedReports()) {
emailBuilder.send(account, parent, root, "report", EmailSender.NOTIFICATION);
sent = true;
}
}
if ( sent ){
accountRepository.markReportSent(account.getId(), now());
}
} catch (Exception ex) {
String message = "Problem building report email for account " + account.getId();
logger.log(Level.WARNING, message, ex);;
new TeamNotificationEvent( message + " : exception: " + ex.getMessage()).fire();
throw new IOException(message, ex);
}
}
UPDATE 2 AFTER ADDING EXTRA DEBUG LOGGING
I see two POSTS in at the same time to the same task queue with the same cursor:
09:35:08.397 2015-04-30 200 0 B 3.78s /ws/notification/daily-report-task-creator
0.1.0.2 - - [30/Apr/2015:01:35:08 -0700] "POST /ws/notification/daily-report-task-creator HTTP/1.1" 200 0 "http://screentimelabs.appspot.com/ws/notification/daily-report-task-creator" "AppEngine-Google; (+http://code.google.com/appengine)" "screentimelabs.appspot.com" ms=3782 cpu_ms=662 queue_name=dailyReports task_name=8168414365365326983 instance=00c61b117c33a909790f0d1882657e04f40b2c7e app_engine_release=1.9.20
09:35:04.618 com.screentime.service.taskqueue.reports.DailyReportTaskCreatorServlet createTasks: createTasks called for filter: ACTIVE with cursor: E-ABAIICO2oQc35zY3JlZW50aW1lbGFic3InCxIHQWNjb3VudCIaamFybW8ua2Fya2thaW5lbkBnbWFpbC5jb20MiAIAFA
09:35:08.432 2015-04-30 200 0 B 8.84s /ws/notification/daily-report-task-creator
0.1.0.2 - - [30/Apr/2015:01:35:08 -0700] "POST /ws/notification/daily-report-task-creator HTTP/1.1" 200 0 "http://screentimelabs.appspot.com/ws/notification/daily-report-task-creator" "AppEngine-Google; (+http://code.google.com/appengine)" "screentimelabs.appspot.com" ms=8837 cpu_ms=1348 queue_name=dailyReports task_name=50170612326424582061 instance=00c61b117c2bffe8de313e96fea8aeb813f4b20f app_engine_release=1.9.20 trace_id=7e5c0348382e66cf4e2c6ba400529fb7
09:34:59.608 com.screentime.service.taskqueue.reports.DailyReportTaskCreatorServlet createTasks: createTasks called for filter: ACTIVE with cursor: E-ABAIICO2oQc35zY3JlZW50aW1lbGFic3InCxIHQWNjb3VudCIaamFybW8ua2Fya2thaW5lbkBnbWFpbC5jb20MiAIAFA
Searching for 1 particular account id I see these requests:
09:35:08.397 2015-04-30 200 0 B 3.78s /ws/notification/daily-report-task-creator
09:35:08.432 2015-04-30 200 0 B 8.84s /ws/notification/daily-report-task-creator
09:35:08.443 2015-04-30 200 0 B 6.73s /ws/notification/daily-report-task-creator
09:35:10.541 2015-04-30 200 0 B 4.03s /ws/notification/daily-report-task-creator
09:35:10.690 2015-04-30 200 0 B 11.09s /ws/notification/daily-report-task-creator
09:35:13.678 2015-04-30 200 0 B 862ms /ws/notification/daily-report-worker
09:35:13.829 2015-04-30 500 0 B 1.21s /ws/notification/daily-report-worker
09:35:14.677 2015-04-30 200 0 B 1.56s /ws/notification/daily-report-worker
09:35:14.961 2015-04-30 200 0 B 346ms /ws/notification/daily-report-worker
Some have repeated cursor values.
I will make a guess because i dont see the task queue code. Its likely that you are not handling errors correctly in the task queue. If a task queue finishes with an error, gae will re-queue it. thus if some emails were already sent, the task will still run again. you need a way to remember what you already processed in the task queue so a retry wont reprocess those.
I have two files one in the server and one is local, I want to get the last modification of both files and see which one is newer. I made a method, but I always get the same result. I tried the test each side, but the if statement make the same decition always.
Here is my code:
public void SyncCheck(FTPClient ftpClient, String remoteFilePath, String savePath) throws IOException, ParseException{
String time = ftpClient.getModificationTime(remoteFilePath);
Date remoteFileDate = timeSplitter(time);
Date LocalFileDate = new Date(new File(savePath).lastModified());
if(remoteFileDate.after(LocalFileDate)){
System.out.println("Remote File is newer: " + remoteFileDate);
}
else{
System.out.println("nothing");
System.out.println("Remote " + remoteFileDate);
System.out.println("Local " + LocalFileDate);
}
}
public Date timeSplitter(String time) throws ParseException{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String timePart = time.split(" ")[1];
Date modificationTime = dateFormat.parse(timePart);
return modificationTime;
}
The result is always this:
nothing
Remote Fri Apr 03 02:20:30 BST 2015
Local Fri Apr 03 03:12:58 BST 2015
No matter is the remote file is newer or older. The other this I notices is that the remote file is modified at 03:20:30, but it is one hour behind always. Is is about anything with time zones?
Or any idea to compare last modification time of one server file vs. a local one ?
There is no standard way to know ftp server timezone, but what you can do is to upload a file and then calculate the time difference between the file time reported by FTP and locally. This must be a method running as a first step of your program to initialize the timezone logic in every client application of yours.
I am creating a new thread to check a folder for new files then sleeping for a defined period of time.
My preference would be to use the ScheduledExecutorService, however, I can't find any documentation to clarify if this waits for the currently running task to complete before starting a new one.
For example, in the following code;
Integer samplingInterval = 30;
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(10);
executorService.scheduleAtFixedRate(new WatchAgent(agentInfo),
0,
samplingInterval,
TimeUnit.SECONDS);
If the run() of WatchAgent takes longer than 30 seconds, will a new agent be created before it finishes?
Secondly, if I create an instance of WatchAgent, can I keep using the same instance for each periodic run?
Per the javadoc of scheduleAtFixedRate:
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
scheduleAtFixedRate by definition takes a single Runnable instance. There is no way for you to provide different instances for each invocation of run. So to answer your question, the same instance will always be used for each periodic run.
Try this test code below.
1) Yes, it seems to wait until run() is finished.
2) Yes, seems it is using the same instance's run method (the one you passed in when you called scheduleAtFixedRate; this makes perfect sense btw).
import java.util.Date;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Test006 {
public static void main(String[] args) {
Object agentInfo = null;
Integer samplingInterval = 30;
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(10);
executorService.scheduleAtFixedRate(new WatchAgent(agentInfo), 0, samplingInterval, TimeUnit.SECONDS);
}
}
class WatchAgent implements Runnable {
public WatchAgent(Object info){
}
public void run(){
try{
System.out.println("Running " + this.hashCode() + " - started on/at " + (new Date()));
Thread.sleep(60000);
System.out.println("Running " + this.hashCode() + " - finished on/at " + (new Date()));
}catch(Exception ex){
ex.printStackTrace();
}
}
}
Output:
Running 1322575120 - started on/at Mon Jul 08 19:58:41 IST 2019
Running 1322575120 - finished on/at Mon Jul 08 19:59:41 IST 2019
Running 1322575120 - started on/at Mon Jul 08 19:59:41 IST 2019
Running 1322575120 - finished on/at Mon Jul 08 20:00:41 IST 2019
Running 1322575120 - started on/at Mon Jul 08 20:00:41 IST 2019
...
I am reading this topic about java Thread.
And there is an example:
import java.util.Vector;
class Producer extends Thread {
static final int MAXQUEUE = 5;
private Vector messages = new Vector();
#Override
public void run() {
try {
while (true) {
putMessage();
//sleep(5000);
}
} catch (InterruptedException e) {
}
}
private synchronized void putMessage() throws InterruptedException {
while (messages.size() == MAXQUEUE) {
wait();
}
messages.addElement(new java.util.Date().toString());
System.out.println("put message");
notify();
//Later, when the necessary event happens, the thread that is running it calls notify() from a block synchronized on the same object.
}
// Called by Consumer
public synchronized String getMessage() throws InterruptedException {
notify();
while (messages.size() == 0) {
wait();//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep.
}
String message = (String) messages.firstElement();
messages.removeElement(message);
return message;
}
}
class Consumer extends Thread {
Producer producer;
Consumer(Producer p) {
producer = p;
}
#Override
public void run() {
try {
while (true) {
String message = producer.getMessage();
System.out.println("Got message: " + message);
//sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
Producer producer = new Producer();
producer.start();
new Consumer(producer).start();
}
}
And the author said:
A possible output sequence:
Got message: Fri Dec 02 21:37:21 EST 2011
put message
put message
put message
put message
put message
Got message: Fri Dec 02 21:37:21 EST 2011
Got message: Fri Dec 02 21:37:21 EST 2011
Got message: Fri Dec 02 21:37:21 EST 2011
Got message: Fri Dec 02 21:37:21 EST 2011
Got message: Fri Dec 02 21:37:21 EST 2011
put message
put message
put message
put message
put message
Got message: Fri Dec 02 21:37:21 EST 2011
Got message: Fri Dec 02 21:37:21 EST 2011
Got message: Fri Dec 02 21:37:21 EST 2011
But when I run this code I got this result:
put message
put message
put message
put message
put message
put message
Got message: Tue Sep 24 16:44:59 CST 2013
Got message: Tue Sep 24 16:45:00 CST 2013
put message
Got message: Tue Sep 24 16:45:00 CST 2013
put message
Got message: Tue Sep 24 16:45:00 CST 2013
put message
..............
What is the problem?
Any one can explain it for me?
The author's entire point is that the order of tasks between different threads is unpredictable. He printed a possible output sequence, but many, many others are possible.
In addition to the already explained output I must add that the book you are reading doesn't seem to be a very good source to learn from. It teaches to:
extend Thread, a notorious bad practice;
invoke wait and notify on a Thread instance—another known, documented bad practice.
use the wait and notify mechanism in the first place, which has mostly been superseded by much more convenient and simpler java.util.concurrent tools such as CountDownLatch, Semaphore, and Phaser.
Your version of output is correct. Because "Got Message" is not possible without "put message". I mean, if there is no message in queue then how can you retrieve the message. Developer in his example might have given sample output which was not actual code run output but self made just for example.
Remember :
[Count of total "Got message" till particular line] will always be <= [Count of total "put message" till that very line]
The only strange thing is that there are 6 consecutive "put message" which seems to be impossible because the maximum queue size is 5.
But this is because the code sequence
producer.getMessage()
System.out.println("Got message: " + message);
is - of course - not atomic and has been interrupted by a thread switch.
By the way - always use notifyAll() instead of notify.