fix(tasks): Make every background task cancellable, queued or running (#177)

Background tasks often couldn't be cancelled, or cancelling didn't stop them:
- A cancel that arrived before the backend registered the request was dropped (build while saving files, multi-repository fetch/pull between repositories). The host now remembers early cancels (bounded, 2 min), and request ids start at a random value per page.
- There was no queue and no common cancel path: backend-reported tasks (LSP progress, deployment transfers) couldn't be cancelled, and tool installs, VCS operations and update checks had no cancel button in Background Tasks.
- Only the direct child process was killed, and JDK / tool archives were extracted without checking for cancellation.

Tool installs and JDK downloads now share a downloads queue; cancelling a queued task removes it without starting any work. Every task cancels through one path that shows "Cancelling…" and then removes it; tasks that can't be interrupted show a disabled cancel button with the reason. IdeEvent::Task carries `cancellable` with a cancel_task command, cancellable LSP progress sends window/workDoneProgress/cancel, installers, curl and tar run in their own process group and are killed as a group, and extraction checks for cancellation between entries.

Claude-Session: https://claude.ai/code/session_01Dq6jQQn8ZhRfkkyj3PRutA
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-10-29 09:05:12 +08:00
1 джерело c6621c5c36
коміт 1c46a1cd04
40 files changed
+888 -148

No files matched your search

+5 -2
Переглянути файл
@@ -25,7 +25,7 @@ import {
} from "@/platform/ipc";
import { useProject } from "@/platform/project";
import { maybeEditorService, notifications, toolWindowService } from "@/workbench/contributions";
import { removeTask, upsertTask } from "@/workbench/tasks";
import { cancelTask, removeTask, upsertTask, useTasks } from "@/workbench/tasks";
import { appendOutput, finishSummary, firstError, messageFiles, type BuildStatus, type ConsoleLine } from "./model";
export const BUILD_TASK_ID = "build:compile";
@@ -248,7 +248,10 @@ function showFailure() {
export function stopBuild() {
const { request } = useBuildRun.getState();
if (request != null) backend.cancel(request);
if (request == null) return;
// Through the task, so its progress says "Cancelling…" until the build has stopped.
if (useTasks.getState().tasks.some((t) => t.id === BUILD_TASK_ID && t.cancel)) cancelTask(BUILD_TASK_ID);
else backend.cancel(request);
}
/** Runs the last build again (the tool window's rerun button). */