дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 03:05:40 +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
@@ -1,6 +1,6 @@
|
||||
use crate::state::AppState;
|
||||
use ide_core::settings::Settings;
|
||||
use ide_core::{EventSink, IdeError, IdeResult, RequestId};
|
||||
use ide_core::{EventSink, IdeError, IdeResult, RequestId, TaskId};
|
||||
use ide_language::LanguageInfo;
|
||||
use ide_workspace::RecentProject;
|
||||
use ide_workspace::settings::SettingsScope;
|
||||
@@ -225,6 +225,14 @@ pub fn cancel_request(state: State<'_, AppState>, id: RequestId) {
|
||||
state.cancel_request(id);
|
||||
}
|
||||
|
||||
/// Stops a background task the backend reported with `cancellable` set; false when it
|
||||
/// has ended or can't be cancelled.
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub fn cancel_task(id: TaskId) -> bool {
|
||||
ide_core::task::cancel(id)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Type)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum LogLevel {
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
use crate::state::AppState;
|
||||
use ide_core::{IdeEvent, IdeResult, IpcPath, RequestId, SharedSink, TaskId};
|
||||
use ide_core::{CancellationToken, IdeEvent, IdeResult, IpcPath, RequestId, SharedSink, TaskId};
|
||||
use ide_remote::{DeployedPath, SyncEntry, SyncStep, TransferReport};
|
||||
use ide_ssh::RemoteEntry;
|
||||
use std::path::PathBuf;
|
||||
use tauri::{State, Window};
|
||||
|
||||
/// Reports a transfer as a background task (status bar progress).
|
||||
fn progress(sink: SharedSink, title: &str) -> (impl FnMut(&str, usize, usize) + Send, impl FnOnce()) {
|
||||
/// Reports a transfer as a background task (status bar progress) whose Cancel fires `token`.
|
||||
fn progress(
|
||||
sink: SharedSink,
|
||||
title: &str,
|
||||
token: CancellationToken,
|
||||
) -> (impl FnMut(&str, usize, usize) + Send, impl FnOnce()) {
|
||||
let id = TaskId::next();
|
||||
let cancel = token;
|
||||
let handle = ide_core::task::on_cancel(id, move || cancel.cancel());
|
||||
let title = title.to_owned();
|
||||
let (s, t) = (sink.clone(), title.clone());
|
||||
let report = move |path: &str, i: usize, n: usize| {
|
||||
let fraction = if n == 0 { None } else { Some(i as f32 / n as f32) };
|
||||
s.emit(IdeEvent::Task { id, title: t.clone(), message: Some(path.to_owned()), fraction, done: false });
|
||||
let message = Some(path.to_owned());
|
||||
s.emit(IdeEvent::Task { id, title: t.clone(), message, fraction, done: false, cancellable: true });
|
||||
};
|
||||
let done = move || {
|
||||
drop(handle);
|
||||
sink.emit(IdeEvent::Task { id, title, message: None, fraction: Some(1.0), done: true, cancellable: false })
|
||||
};
|
||||
let done = move || sink.emit(IdeEvent::Task { id, title, message: None, fraction: Some(1.0), done: true });
|
||||
(report, done)
|
||||
}
|
||||
|
||||
@@ -34,7 +44,7 @@ pub async fn deploy_upload(
|
||||
) -> IdeResult<TransferReport> {
|
||||
let project = state.project(window.label())?;
|
||||
let token = state.begin_request(request);
|
||||
let (mut report, done) = progress(project.sink.clone(), "Uploading");
|
||||
let (mut report, done) = progress(project.sink.clone(), "Uploading", token.clone());
|
||||
let r = state
|
||||
.remote
|
||||
.upload(&project.settings.effective(), &project.root, server.as_deref(), &local(paths), token, &mut report)
|
||||
@@ -56,7 +66,7 @@ pub async fn deploy_download(
|
||||
) -> IdeResult<TransferReport> {
|
||||
let project = state.project(window.label())?;
|
||||
let token = state.begin_request(request);
|
||||
let (mut report, done) = progress(project.sink.clone(), "Downloading");
|
||||
let (mut report, done) = progress(project.sink.clone(), "Downloading", token.clone());
|
||||
let r = state
|
||||
.remote
|
||||
.download(&project.settings.effective(), &project.root, server.as_deref(), &local(paths), token, &mut report)
|
||||
@@ -108,7 +118,7 @@ pub async fn deploy_sync(
|
||||
) -> IdeResult<TransferReport> {
|
||||
let project = state.project(window.label())?;
|
||||
let token = state.begin_request(request);
|
||||
let (mut report, done) = progress(project.sink.clone(), "Synchronizing");
|
||||
let (mut report, done) = progress(project.sink.clone(), "Synchronizing", token.clone());
|
||||
let r = state
|
||||
.remote
|
||||
.sync(&project.settings.effective(), &project.root, server.as_deref(), &steps, token, &mut report)
|
||||
|
||||
@@ -71,6 +71,7 @@ pub fn builder() -> tauri_specta::Builder<tauri::Wry> {
|
||||
app::project_rename,
|
||||
app::project_roots,
|
||||
app::cancel_request,
|
||||
app::cancel_task,
|
||||
app::log_frontend,
|
||||
agent::agent_subscribe,
|
||||
agent::agent_providers,
|
||||
|
||||
Reference in new issue
Заблокувати користувача