fix(runtime): cancel de background task immédiat et fiable depuis le workstate (#199, QA verte)
Transforme l'annulation d'une background task en contrat immédiat, observable et non-best-effort: - domain/background_task: états Cancelling/Cancelled/CancelFailed et transitions idempotentes; un kill PTY qui échoue est surfacé en CancelFailed plutôt qu'en succès silencieux. - infrastructure/runner + store: cancel effectif de la task ciblée, reconcile marque Cancelling même sans live handle, et départage CancelFailed des tâches pending au boot. - application/background + workstate + orchestrator/wake: chemin de cancel initié depuis le workstate, projection synchronisée de l'état (pas d'attente d'un cycle ambigu). - frontend: projection workstate de l'état cancelled/cancelling/cancelFailed (cancellingRow/cancelFailedRow/cancelButtons), normalization et services. Tests QA verts: background_task_cancel, background_task_runner cancel_wins_even_if_output_is_still_available, background_task_store reconcile_marks_cancelling_without_live_handle_cancel_failed_and_pending, workstate.test.tsx.
This commit is contained in:
@ -28,12 +28,16 @@ pub enum BackgroundTaskState {
|
||||
Running,
|
||||
/// Suspended while waiting for an external event.
|
||||
Waiting,
|
||||
/// Cancellation has been accepted and the runner is stopping the resource.
|
||||
Cancelling,
|
||||
/// Finished successfully.
|
||||
Completed,
|
||||
/// Finished with an error.
|
||||
Failed,
|
||||
/// Cancelled before natural completion.
|
||||
Cancelled,
|
||||
/// Cancellation was requested but the runner could not stop the resource.
|
||||
CancelFailed,
|
||||
/// Expired after its deadline.
|
||||
Expired,
|
||||
}
|
||||
@ -44,7 +48,7 @@ impl BackgroundTaskState {
|
||||
pub const fn is_terminal(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Completed | Self::Failed | Self::Cancelled | Self::Expired
|
||||
Self::Completed | Self::Failed | Self::Cancelled | Self::CancelFailed | Self::Expired
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -342,6 +346,13 @@ pub enum BackgroundTaskResult {
|
||||
/// Cancellation reason.
|
||||
reason: String,
|
||||
},
|
||||
/// Cancellation failed.
|
||||
CancelFailed {
|
||||
/// Completion timestamp, epoch milliseconds.
|
||||
finished_at_ms: u64,
|
||||
/// Human-readable error.
|
||||
error: String,
|
||||
},
|
||||
/// Expired completion.
|
||||
Expired {
|
||||
/// Completion timestamp, epoch milliseconds.
|
||||
@ -375,6 +386,7 @@ impl BackgroundTaskResult {
|
||||
Self::Success { finished_at_ms, .. }
|
||||
| Self::Failure { finished_at_ms, .. }
|
||||
| Self::Cancelled { finished_at_ms, .. }
|
||||
| Self::CancelFailed { finished_at_ms, .. }
|
||||
| Self::Expired { finished_at_ms, .. } => *finished_at_ms,
|
||||
}
|
||||
}
|
||||
@ -408,6 +420,9 @@ impl BackgroundTaskResult {
|
||||
Self::Cancelled { reason, .. } | Self::Expired { reason, .. } => {
|
||||
validate_text("reason", reason)?;
|
||||
}
|
||||
Self::CancelFailed { error, .. } => {
|
||||
validate_text("error", error)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -417,6 +432,7 @@ impl BackgroundTaskResult {
|
||||
Self::Success { .. } => BackgroundTaskState::Completed,
|
||||
Self::Failure { .. } => BackgroundTaskState::Failed,
|
||||
Self::Cancelled { .. } => BackgroundTaskState::Cancelled,
|
||||
Self::CancelFailed { .. } => BackgroundTaskState::CancelFailed,
|
||||
Self::Expired { .. } => BackgroundTaskState::Expired,
|
||||
}
|
||||
}
|
||||
@ -459,13 +475,22 @@ pub enum BackgroundTaskError {
|
||||
}
|
||||
|
||||
fn is_transition_allowed(from: BackgroundTaskState, to: BackgroundTaskState) -> bool {
|
||||
use BackgroundTaskState::{Cancelled, Completed, Expired, Failed, Queued, Running, Waiting};
|
||||
use BackgroundTaskState::{
|
||||
CancelFailed, Cancelled, Cancelling, Completed, Expired, Failed, Queued, Running, Waiting,
|
||||
};
|
||||
|
||||
matches!(
|
||||
(from, to),
|
||||
(Queued, Running | Cancelled | Expired)
|
||||
| (Running, Waiting | Completed | Failed | Cancelled | Expired)
|
||||
| (Waiting, Running | Completed | Failed | Cancelled | Expired)
|
||||
(
|
||||
Queued,
|
||||
Running | Cancelling | Cancelled | CancelFailed | Expired
|
||||
) | (
|
||||
Running,
|
||||
Waiting | Cancelling | Completed | Failed | Cancelled | CancelFailed | Expired
|
||||
) | (
|
||||
Waiting,
|
||||
Running | Cancelling | Completed | Failed | Cancelled | CancelFailed | Expired
|
||||
) | (Cancelling, Cancelled | CancelFailed | Expired)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user