дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
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
Цей коміт міститься в:
1 джерело
c6621c5c36
коміт
1c46a1cd04
40 files changed
+888
-148
No files matched your search
@@ -6,9 +6,10 @@ import { Channel } from "@tauri-apps/api/core";
|
||||
import { create } from "zustand";
|
||||
import type { GitOperation, RemoteOp } from "@/bindings";
|
||||
import { tx } from "@/platform/i18n";
|
||||
import { call, commands, emitLocalIdeEvent, isCancelled, nextRequestId } from "@/platform/ipc";
|
||||
import { call, commands, isCancelled, nextRequestId } from "@/platform/ipc";
|
||||
import { editorsFor } from "@/editor/api";
|
||||
import { maybeEditorService, notifications } from "@/workbench/contributions";
|
||||
import { cancelTask, upsertTaskSoon, useTasks } from "@/workbench/tasks";
|
||||
import { progressFraction } from "./model";
|
||||
import { currentRepo, refreshNow, repoName, useVcs } from "./store";
|
||||
|
||||
@@ -129,7 +130,10 @@ export function lastRemoteFailure(): string | null {
|
||||
}
|
||||
|
||||
export function cancelRemote() {
|
||||
if (activeRemote !== null) void commands.cancelRequest(activeRemote);
|
||||
if (activeRemote === null) return;
|
||||
const taskId = `vcs:${activeRemote}`;
|
||||
if (useTasks.getState().tasks.some((t) => t.id === taskId)) cancelTask(taskId);
|
||||
else void commands.cancelRequest(activeRemote);
|
||||
}
|
||||
|
||||
/** Every repository of the project (Fetch and Update Project act on all of them, as in IDEA). */
|
||||
@@ -154,11 +158,12 @@ export async function runRemote(
|
||||
const [progressText, doneTitle] = REMOTE_TITLE[op.op];
|
||||
const progressTitle = tx(progressText);
|
||||
const request = nextRequestId();
|
||||
const taskId = 900_000 + request;
|
||||
const taskId = `vcs:${request}`;
|
||||
activeRemote = request;
|
||||
useVcs.setState({ remoteBusy: progressTitle });
|
||||
const cancel = () => void commands.cancelRequest(request);
|
||||
const task = (message: string | null, fraction: number | null, done: boolean) =>
|
||||
emitLocalIdeEvent({ type: "task", id: taskId, title: progressTitle, message, fraction, done });
|
||||
upsertTaskSoon({ id: taskId, title: progressTitle, message, fraction, done, cancel });
|
||||
task(detail ?? null, null, false);
|
||||
notifications().notify({
|
||||
group: "vcs",
|
||||
@@ -220,13 +225,16 @@ export async function runRemote(
|
||||
const cancelled = isCancelled(e);
|
||||
lastRemoteError = cancelled ? null : errorMessage(e);
|
||||
logConsole(cancelled ? "info" : "err", cancelled ? `${doneTitle} cancelled` : errorMessage(e));
|
||||
notifications().notify({
|
||||
group: "vcs",
|
||||
level: cancelled ? "warning" : "error",
|
||||
key: "vcs.remote",
|
||||
title: cancelled ? `${doneTitle} cancelled` : `${doneTitle} failed`,
|
||||
body: cancelled ? undefined : errorMessage(e),
|
||||
});
|
||||
// The user asked for it: the progress balloon just goes away.
|
||||
if (cancelled) notifications().expire?.("vcs.remote");
|
||||
else
|
||||
notifications().notify({
|
||||
group: "vcs",
|
||||
level: "error",
|
||||
key: "vcs.remote",
|
||||
title: `${doneTitle} failed`,
|
||||
body: errorMessage(e),
|
||||
});
|
||||
return false;
|
||||
} finally {
|
||||
task(null, 1, true);
|
||||
@@ -320,12 +328,13 @@ export async function runGitOperation(op: GitOperation, opts: GitOperationOption
|
||||
}
|
||||
await saveAll();
|
||||
const request = nextRequestId();
|
||||
const taskId = 900_000 + request;
|
||||
const taskId = `vcs:${request}`;
|
||||
activeRemote = request;
|
||||
const progress = tx(opts.progress);
|
||||
useVcs.setState({ remoteBusy: progress });
|
||||
const cancel = () => void commands.cancelRequest(request);
|
||||
const task = (message: string | null, done: boolean) =>
|
||||
emitLocalIdeEvent({ type: "task", id: taskId, title: progress, message, fraction: done ? 1 : null, done });
|
||||
upsertTaskSoon({ id: taskId, title: progress, message, fraction: done ? 1 : null, done, cancel });
|
||||
task(null, false);
|
||||
notifications().notify({
|
||||
group: "vcs",
|
||||
@@ -357,14 +366,14 @@ export async function runGitOperation(op: GitOperation, opts: GitOperationOption
|
||||
logConsole(cancelled ? "info" : "err", cancelled ? `${opts.failure}: cancelled` : message);
|
||||
notifications().expire?.("vcs.operation");
|
||||
await refreshNow();
|
||||
const handled = !cancelled && opts.onError ? await opts.onError(message) : false;
|
||||
const handled = cancelled || (opts.onError ? await opts.onError(message) : false);
|
||||
if (!handled)
|
||||
notifications().notify({
|
||||
group: "vcs",
|
||||
level: cancelled ? "warning" : "error",
|
||||
level: "error",
|
||||
key: "vcs.operation",
|
||||
title: cancelled ? `${opts.progress} cancelled` : opts.failure,
|
||||
body: cancelled ? undefined : message,
|
||||
title: opts.failure,
|
||||
body: message,
|
||||
});
|
||||
return false;
|
||||
} finally {
|
||||
|
||||
Reference in new issue
Заблокувати користувача