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
Vertx.cancelTimer() can return true when timer fires #2912
Comments
can you provide a reproducer ? |
I don't think a reproducer is warranted, given that it is clear by inspection of the following code (taken from
As written, the Sorry if this is an over-explanantion, I don't mean to insult anybody's intelligence. Let me know if I am missing something. |
this is a fine explanation. I believe that when the timer fires, the handler should perform a CAS operation as well to execute the operation and signal the caller of |
I think that changing the
should fix the problem, I will come up with tests that reproduce this issue in the coming days. |
I think this could even be simplified to remove the |
that being said, I think that even before this could have relied on the |
in practice actually we cannot rely on the result if |
… in a racy manner, instead use the existing timeouts map and rely on the timeouts map removal to grant ownership of the timer termination (cancellation or timeout). - fixes #2912
Looks good to me, thank you! |
… in a racy manner, instead use the existing timeouts map and rely on the timeouts map removal to grant ownership of the timer termination (cancellation or timeout). - fixes eclipse-vertx#2912
Has this been fixed? We are facing similar issue. |
Has this been fixed? We are facing similar issue. |
@nareshsoni02 it should be fixed, if it's not then it's a bug |
When i call Vertx.cancelTimer(id) it returns true. But even after that it run handler code 1 or 2 times. This happens under load testing. |
can you provide a reproducer project ? |
I think that the current code is incorrect and racy, do you have a reproducer ? |
actually it seems correct but too complicated :-) |
@nareshsoni02 if you can provide a reproducer it would be great . Otherwise the code itself is not complicated, the timer cancellation will return whether the timer was still in the public boolean cancelTimer(long id) {
InternalTimerHandler handler = timeouts.remove(id);
if (handler != null) {
handler.cancel();
return true;
} else {
return false;
}
} if (timeouts.remove(timerID) != null) {
handler.handle(timerID);
} As the timer can only be removed once, it is either executed or cancelled from any thread perspective as the timeouts map is a concurrent map that will not return |
|
can you provide a full reproducer project ?
… On 27 Apr 2020, at 21:37, nareshsoni02 ***@***.***> wrote:
public Future<Task> pollForTaskCompletion(RoutingContext context, String taskId) {
Future<Task> completedTaskFuture = Future.future();
long timerId = vertx.setPeriodic(POLLING_INTERVAL, timer -> {
Future<Task> taskFuture = service.getTask(taskId);
taskFuture.setHandler(taskAsync -> {
if(taskAsync.succeeded()){
Task task = taskAsync.result();
completedTaskFuture.complete(task);
} else{
//Cancel task if more than polling time
cancelTask();
}
});
});
Future<Task> timerCompletionFuture = Future.future();
completedTaskFuture.setHandler(taskAsyncResult ->{
vertx.cancleTimer(timerId);
if(taskAsyncResult.succeeded()){
timerCompletionFuture.complete(taskAsyncResult.result());
} else{
timerCompletionFuture.fail(taskAsyncResult.cause());
}
});
return timerCompletionFuture;
}
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub <#2912 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AABXDCQ5PUXVZHCWPPWKZKTROXNI3ANCNFSM4HGECPOA>.
|
The API contract for
Vertx.cancelTimer()
appears to indicate that if it returns true, the timer has been successfully canceled. However, the timer handler is not properly synchronized with the timer flag, so the handler can see thecancelled
flag is false and start the handler execution before the CAS in thecancel()
method runs.Currently, we have to do our own synchronization around timers to ensure that when a timer fires indicating a timeout, we are guaranteed the handler does not also execute. It would be better if
InternalTimerHandler.handle()
also did acancelled.compareAndSet(false, true)
and only executed the handler when the CAS is successful, ensuring that canceled timers are guaranteed not to execute their handlers.The text was updated successfully, but these errors were encountered: