Skip to content
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

Fix a task startup race #180546

Merged
merged 3 commits into from May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 0 additions & 11 deletions src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts
Expand Up @@ -220,8 +220,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer

protected _taskRunningState: IContextKey<boolean>;

private _inProgressTasks: Set<string> = new Set();

protected _outputChannel: IOutputChannel;
protected readonly _onDidStateChange: Emitter<ITaskEvent>;
private _waitForSupportedExecutions: Promise<void>;
Expand Down Expand Up @@ -1831,12 +1829,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer

private async _executeTask(task: Task, resolver: ITaskResolver, runSource: TaskRunSource): Promise<ITaskSummary> {
let taskToRun: Task = task;
const qualifiedLabel = task.getQualifiedLabel();
if (this._inProgressTasks.has(qualifiedLabel)) {
this._logService.info('Prevented duplicate task from running', qualifiedLabel);
return { exitCode: 0 };
}
this._inProgressTasks.add(qualifiedLabel);
if (await this._saveBeforeRun()) {
await this._configurationService.reloadConfiguration();
await this._updateWorkspaceTasks();
Expand All @@ -1852,10 +1844,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
await ProblemMatcherRegistry.onReady();
const executeResult = runSource === TaskRunSource.Reconnect ? this._getTaskSystem().reconnect(taskToRun, resolver) : this._getTaskSystem().run(taskToRun, resolver);
if (executeResult) {
this._inProgressTasks.delete(qualifiedLabel);
return this._handleExecuteResult(executeResult, runSource);
}
this._inProgressTasks.delete(qualifiedLabel);
return { exitCode: 0 };
}

Expand Down Expand Up @@ -1915,7 +1905,6 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
if (!this._taskSystem) {
return { success: true, task: undefined };
}
this._inProgressTasks.delete(task.getQualifiedLabel());
return this._taskSystem.terminate(task);
}

Expand Down
11 changes: 7 additions & 4 deletions src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts
Expand Up @@ -286,17 +286,20 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem {
public run(task: Task, resolver: ITaskResolver, trigger: string = Triggers.command): ITaskExecuteResult {
task = task.clone(); // A small amount of task state is stored in the task (instance) and tasks passed in to run may have that set already.
const recentTaskKey = task.getRecentlyUsedKey() ?? '';
const validInstance = task.runOptions && task.runOptions.instanceLimit && this._instances[recentTaskKey] && this._instances[recentTaskKey].instances < task.runOptions.instanceLimit;
const validInstance = !this._instances[recentTaskKey] || this._instances[recentTaskKey].instances < ((task.runOptions && task.runOptions.instanceLimit) ?? 0);
const instance = this._instances[recentTaskKey] ? this._instances[recentTaskKey].instances : 0;
this._currentTask = new VerifiedTask(task, resolver, trigger);
if (instance > 0) {
task.instance = this._instances[recentTaskKey].counter;
}
const lastTaskInstance = this.getLastInstance(task);
const terminalData = lastTaskInstance ? this._activeTasks[lastTaskInstance.getMapKey()] : undefined;
if (terminalData && terminalData.promise && !validInstance && !task.configurationProperties.dependsOn?.length) {
this._lastTask = this._currentTask;
return { kind: TaskExecuteKind.Active, task: terminalData.task, active: { same: true, background: task.configurationProperties.isBackground! }, promise: terminalData.promise };
if (!validInstance) {
meganrogge marked this conversation as resolved.
Show resolved Hide resolved
if (terminalData && terminalData.promise) {
this._lastTask = this._currentTask;
return { kind: TaskExecuteKind.Active, task: terminalData.task, active: { same: true, background: task.configurationProperties.isBackground! }, promise: terminalData.promise };
}
throw new TaskError(Severity.Warning, nls.localize('TaskSystem.active', 'There is already a task running. Terminate it first before executing another task.'), TaskErrors.RunningTask);
}

try {
Expand Down