New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ZOOKEEPER-2694:sync CLI command does not wait for result from server #823
Conversation
maoling
commented
Feb 19, 2019
- Thanks the original work from arshad.mohammad
- more details in ZOOKEEPER-2694
2908251
to
be831e2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall the fix looks good to me, just having a few questions.
} | ||
}, null); | ||
} catch (IllegalArgumentException ex) { | ||
latch.await(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be safer to wait for some reasonable amount of time (30s) rather than waiting indefinitely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it can be a parameter with a default of 30secs
} catch (IllegalArgumentException ex) { | ||
latch.await(); | ||
out.println("Sync returned " + resultCode[0]); | ||
} catch (IllegalArgumentException | InterruptedException ex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to catch InterruptedException
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
latch.await
needs this, my sweet IDEA help me do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's handled properly here. You basically swallowing and hiding it inside a MalformedPathException
which is wrong.
} | ||
}, null); | ||
} catch (IllegalArgumentException ex) { | ||
latch.await(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it can be a parameter with a default of 30secs
@@ -55,14 +57,18 @@ public CliCommand parse(String[] cmdArgs) throws CliParseException { | |||
@Override | |||
public boolean exec() throws CliException { | |||
String path = args[1]; | |||
CountDownLatch latch = new CountDownLatch(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about a more modern CompletableFuture?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for mentioning this good option:CompletableFuture
,but for issue,IMO,we don't need to kill a chicken with the sword:D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CompletableFuture
has specifically been designed for scenarios like this. As far as I'm concerned. Let me check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this?
@Override
public boolean exec() throws CliException {
String path = args[1];
CompletableFuture<Integer> cf = new CompletableFuture<>();
try {
zk.sync(path, new AsyncCallback.VoidCallback() {
public void processResult(int rc, String path, Object ctx) {
cf.complete(rc);
}
}, null);
try {
int resultCode = cf.get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);
out.println("Sync returned " + resultCode);
} catch (TimeoutException ex) {
out.println("Sync is timeout within " + CONNECTION_TIMEOUT + " ms");
}
} catch (IllegalArgumentException | InterruptedException | ExecutionException ex) {
throw new MalformedPathException(ex.getMessage());
}
return false;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anmolnar Great work. you are so sweet! it's very elegant especially when we want to transfer the result value.
Cc:Thanks @eolivelli for mentioning this good option:CompletableFuture
again.
@@ -55,14 +57,18 @@ public CliCommand parse(String[] cmdArgs) throws CliParseException { | |||
@Override | |||
public boolean exec() throws CliException { | |||
String path = args[1]; | |||
CountDownLatch latch = new CountDownLatch(1); | |||
final int[] resultCode = new int[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is an array necessary here? Wouldn't a plain integer be sufficient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when use a plain integer, a anonymous Inner Class needs it to be modified with final
,then we cannot assignment and transfer the result outside.
c219e8b
to
fe6bc5c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 LGTM
ping @anmolnar |
@phunt @eolivelli Would you like to take another look? |
@@ -30,6 +35,7 @@ | |||
|
|||
private static Options options = new Options(); | |||
private String[] args; | |||
public static final int CONNECTION_TIMEOUT = 30000;//30s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about 'SYNC_TIMEOUT' ?
It is not used for 'comnection'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use TimeUnit so that it is self documenting.
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/TimeUnit.html
TimeUnit.SECONDS.toMillis(30L)
int resultCode = cf.get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); | ||
out.println("Sync returned " + resultCode); | ||
} catch (TimeoutException ex) { | ||
out.println("Sync is timeout within " + CONNECTION_TIMEOUT + " ms"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we throw an error?
The command may not have succeeded
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eolivelli pardon me.I may not get your idea clearly.
Do you mean that throwing this TimeoutException
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maoling yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this code need it's own 'try' block? Can this catch be moved to the outer 'try' statement?
} catch (IllegalArgumentException ex) { | ||
throw new MalformedPathException(ex.getMessage()); | ||
} catch (InterruptedException | ExecutionException ex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About catching InterruptedException
: http://www.javapractices.com/topic/TopicAction.do?Id=251
We don't do anywhere else in our code which maybe not a good practice.
What do you think @belugabehr ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about it.
In this specific case we don't care. The CLI will exit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you catch the Interrupted exception, it clears the Thread's state. I would separate the catch into two blocks and be sure to reinstate the flag to 'interrupted' so that any other code will also quickly exit.
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new CliWrapperException(ie);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but in this case it is not really needed.
We can add it but not so important
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's always best to do it the "right" way... it will insulate the code from changes later when it may become needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's missing from everywhere else in the code unfortunately.
There's no harm adding it here anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, better to add.
Better to file a JIRA for fixing it every where
…of handling the InterruptedException
ping @anmolnar @eolivelli |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good
retest maven build |
- Thanks the original work from [arshad.mohammad ](https://issues.apache.org/jira/secure/ViewProfile.jspa?name=arshad.mohammad) - more details in [ZOOKEEPER-2694](https://issues.apache.org/jira/browse/ZOOKEEPER-2694) Author: maoling <maoling199210191@sina.com> Reviewers: eolivelli@apache.org, andor@apache.org Closes #823 from maoling/ZOOKEEPER-2694 and squashes the following commits: 41723cd [maoling] print the resultCode when sync has failed 95123c0 [maoling] make the Sync more user-friendly a3ce170 [maoling] SYNC_TIMEOUT & use the TimeUnit.SECONDS.toMillis & a responsible way of handling the InterruptedException df0bf73 [maoling] CliWrapperException 52c3ad0 [maoling] change CountDownLatch to CompletableFuture 0cc1edd [maoling] add the wait_timeout: 30s cf01294 [maoling] ZOOKEEPER-2694:sync CLI command does not wait for result from server (cherry picked from commit e2bb6e8) Signed-off-by: Andor Molnar <andor@apache.org>
Patch committed to 3.5 and master branches. Thanks @maoling ! |
- Thanks the original work from [arshad.mohammad ](https://issues.apache.org/jira/secure/ViewProfile.jspa?name=arshad.mohammad) - more details in [ZOOKEEPER-2694](https://issues.apache.org/jira/browse/ZOOKEEPER-2694) Author: maoling <maoling199210191@sina.com> Reviewers: eolivelli@apache.org, andor@apache.org Closes apache#823 from maoling/ZOOKEEPER-2694 and squashes the following commits: 41723cd [maoling] print the resultCode when sync has failed 95123c0 [maoling] make the Sync more user-friendly a3ce170 [maoling] SYNC_TIMEOUT & use the TimeUnit.SECONDS.toMillis & a responsible way of handling the InterruptedException df0bf73 [maoling] CliWrapperException 52c3ad0 [maoling] change CountDownLatch to CompletableFuture 0cc1edd [maoling] add the wait_timeout: 30s cf01294 [maoling] ZOOKEEPER-2694:sync CLI command does not wait for result from server