-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
TaskService.runTask(...) not safe for parallel Execution #9806
Comments
The run task method looks something like this: async runTask(task: TaskConfiguration, option?: RunTaskOption): Promise<TaskInfo | undefined> {
const runningTasksInfo: TaskInfo[] = await this.getRunningTasks();
if (findRunningTask(runningTaskInfo, task) { // the task is active
const selectedAction = await this.messageService.info(`The task '${taskName}' is already active`, 'Terminate Task', 'Restart Task');
if (selectedAction === 'Terminate Task') {
await this.terminateTask(matchedRunningTaskInfo);
} else if (selectedAction === 'Restart Task') {
return this.restartTask(matchedRunningTaskInfo, option);
}
} else { // run task as the task is not active
return this.doRunTask(task, option);
}
} The trouble is that this code is really equivalent to this one: runTask(task: TaskConfiguration, option?: RunTaskOption): Promise<TaskInfo | undefined> {
return this.getRunningTasks().then(runningTaskInfo => {
if (findRunningTask(runningTaskInfo, task) { // the task is active
const selectedAction = await this.messageService.info(`The task '${taskName}' is already active`, 'Terminate Task', 'Restart Task');
...
});
} So the method immediately returns and can process the next mouse click and before we've added the newly started task to the set of running tasks. |
@tsmaeder do you know if |
@vince-fugnitto I don't believe comparisons have anything to do with it, otherwise the problem would not be timing-dependent. The fact that we're not seeing the problem upstream is due to the fact that the UI for starting a task is not immediate like a mouse click. |
I haven't been able to reproduce with a pure plugin approach so far: however, I have no trouble when I change TestService.runTask(...) like so:
so this correct functioning is dependent on the exact promise we're getting back from @caseyflynn-google this is an exampl of why I'm not a fan of async/wait: it makes it too easy to fall into the trap of thinking the code is synchronous when it can be in fact a complex interleaving of various continuations. |
I'm aware of that, but using debounce will fail again when the system is slow and it's a general solution for a specific problem. The tree widget is not the source of the problem. |
I was able to reproduce the issue by making the TaskServerImpl.getTasks() method slower like so:
So the issue is real and it's a timing issue: |
The attached plugin adds a view to the navigator showing all tasks. With the above delay in the back end, multi-clicking on tasks in the view will run multiple copies of the same task (timing dependent, of course) |
The source lives here: https://github.com/tsmaeder/prefs-explorer |
Bug Description:
When invoking
TaskService.runTask(...)
twice in a row for the same task, you can run into a race condition: the second execution of the method will not detect that the task is already running and therefore we end up executing the task twice instead of asking the user to cancel/restart the task.Steps to Reproduce:
I don't have an upstream reproducing scenario right now, but in Che, it reproduces since we have a tree view that you can just click on to run tasks. Double-clicking reproduces the issue: eclipse-che/che#19821
Additional Information
The text was updated successfully, but these errors were encountered: