дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
feat(plugins): renew the background budget while a task reports (#2055)
Closes #2053 A call that begins a background task gets the longer `background` budget, but it was armed once, so a task that kept calling `report` was still killed at the first deadline. Each `report` and `is-cancelled` now renews it (the deadline only moves forward; silent work still times out), up to a 30-minute ceiling per task. User Cancel, disable and unload still interrupt the task, teardown interrupts a running task promptly, and cancellation is counted once. WIT change is documentation only. Verified on macOS with a 75 s task. Co-authored-by: chaoes <[email protected]>
Цей коміт міститься в:
1 джерело
1446d5592c
коміт
6373bce476
66 files changed
+108
-38
No files matched your search
@@ -656,6 +656,33 @@ fn plugin_processes_end_with_their_owner() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A task that keeps reporting progress is still working: each report renews
|
||||
/// the background budget, so the call outlives the 400 ms it began with. A task
|
||||
/// that goes quiet is still cut off (see `tasks_that_stop_reporting_are_cut_off`).
|
||||
#[test]
|
||||
fn a_reporting_task_outlives_its_background_budget() {
|
||||
let f = fixture(Limits {
|
||||
timeout: Duration::from_millis(1_000),
|
||||
background: Duration::from_millis(2_000),
|
||||
..Limits::default()
|
||||
});
|
||||
f.install(&misbehave_pkg());
|
||||
if f.host.set_capability("misbehave", "process:git", true).is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Twenty-five waits of 100 ms: 2.5 s of wall time, more than the
|
||||
// budget, spent inside the host rather than the plugin.
|
||||
let started = std::time::Instant::now();
|
||||
let out = f.run("misbehave", "patient", None).expect("a patient task").expect("a result");
|
||||
let took = started.elapsed();
|
||||
assert_eq!(out, "still here");
|
||||
assert!(took >= Duration::from_millis(2_500), "it really ran the waits: {took:?}");
|
||||
|
||||
let info = f.host.info_of("misbehave").unwrap();
|
||||
assert_eq!((info.status, info.stats.crashes, info.stats.errors), (PluginStatus::Active, 0, 0), "{info:?}");
|
||||
}
|
||||
|
||||
/// A missing capability is an error the plugin can handle, not a trap.
|
||||
#[test]
|
||||
fn ungranted_capabilities_are_denied_not_trapped() {
|
||||
@@ -932,7 +959,7 @@ fn idle_instances_are_reclaimed_and_schedules_reactivate() {
|
||||
assert_eq!(f.host.instances(), 0);
|
||||
let info = f.host.info_of("misbehave").unwrap();
|
||||
assert_eq!((info.status, info.stats.reclaims), (PluginStatus::Inactive, 1));
|
||||
assert_eq!(f.command_titles("misbehave").len(), 23, "contributions stay");
|
||||
assert_eq!(f.command_titles("misbehave").len(), 24, "contributions stay");
|
||||
assert_eq!(f.run("misbehave", "echo", Some("y")).unwrap().as_deref(), Some("y"));
|
||||
assert_eq!(f.host.info_of("misbehave").unwrap().stats.activations, 2);
|
||||
|
||||
|
||||
@@ -868,11 +868,7 @@ impl tasks::Host for StoreData {
|
||||
let id = self.host.task_begin(self.client(), clip(title, crate::runtime::MAX_TITLE), cancellable, token);
|
||||
self.open_tasks.push(id);
|
||||
// The call may now run for the background budget.
|
||||
let extended = self.call_started + self.limits.background;
|
||||
if extended > self.deadline {
|
||||
self.deadline = extended;
|
||||
self.timeout = self.limits.background;
|
||||
}
|
||||
self.renew_background(self.call_started);
|
||||
self.push(TaskRes { id })
|
||||
}
|
||||
}
|
||||
@@ -887,6 +883,10 @@ impl tasks::HostTask for StoreData {
|
||||
) -> wasmtime::Result<()> {
|
||||
let id = self.table.get(&this)?.id;
|
||||
let now = Instant::now();
|
||||
// A task that is still reporting is still working: the call gets another
|
||||
// background budget, so long work isn't cut off at the first deadline
|
||||
// while a task that goes quiet still is.
|
||||
self.renew_background(now);
|
||||
// At most ~10 updates per second reach the UI.
|
||||
if self.last_report.is_none_or(|t| now.duration_since(t).as_millis() >= 100) || total.is_some_and(|t| done >= t)
|
||||
{
|
||||
@@ -898,6 +898,8 @@ impl tasks::HostTask for StoreData {
|
||||
|
||||
fn is_cancelled(&mut self, this: Resource<TaskRes>) -> wasmtime::Result<bool> {
|
||||
let id = self.table.get(&this)?.id;
|
||||
// Asking whether to stop is the same sign of life as reporting is.
|
||||
self.renew_background(Instant::now());
|
||||
Ok(self.cancel.token().is_cancelled() || self.host.task_cancelled(id))
|
||||
}
|
||||
|
||||
@@ -910,6 +912,17 @@ impl tasks::HostTask for StoreData {
|
||||
}
|
||||
|
||||
impl StoreData {
|
||||
/// Lets the running call reach `from` plus the background budget (the
|
||||
/// longer of it and what was left), so a task that keeps saying it is alive
|
||||
/// isn't cut off at the first deadline.
|
||||
fn renew_background(&mut self, from: Instant) {
|
||||
let extended = from + self.limits.background;
|
||||
if extended > self.deadline {
|
||||
self.deadline = extended;
|
||||
self.timeout = self.limits.background;
|
||||
}
|
||||
}
|
||||
|
||||
/// What is left of the running call's wall-clock budget (host operations
|
||||
/// can't be interrupted by the epoch callback, so they get this as timeout).
|
||||
fn remaining(&self) -> Duration {
|
||||
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
24726dac5ce264f5d451956def099e0002ec721e4828bc7852ad1dcabcb4bcba
|
||||
54bad5e7b66e800a70e9e8a3189be3c18b815b1020f0718e9f63b6d0d116f700
|
||||
Бінарний файл не відображається.
+1
-1
@@ -1 +1 @@
|
||||
833c378fabd0c3ec71e5c372e51049cb4fcd8d58e4992199eaf6090b3c1235d8
|
||||
d3094365391dba5c9d65f506b4faa7abf3e4cf3906b94bbd058995efda105922
|
||||
Бінарний файл не відображається.
+1
-1
@@ -1 +1 @@
|
||||
f757407f530839b8c43697e310926c5b141231bd8f2781ac92eee3a9de3f0f30
|
||||
93247e39cda6a6174fa44dc27ea4b919efb563c5540b77937b740d2de94c7cbb
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
99cba883e8030d7679db366a4b18b8c456afccbcbc949e0d7411adc6411f2e00
|
||||
1c5c1ce6d465aa201e39adf6c02e32f0d324d312b50371dd4f248b77ae8cda30
|
||||
Бінарний файл не відображається.
+1
-1
@@ -1 +1 @@
|
||||
afcf583238dddd20d0d709ce7619fada0e60916f9e3c039569d37dec75354471
|
||||
5f0877c4438f91dbb4069c733e9f2a214e366ec6e4c295c5c798a28ea75a5400
|
||||
Бінарний файл не відображається.
+1
-1
@@ -1 +1 @@
|
||||
a1ce41144630be398bb63cffca26005955de0511a17c71dc286e7762b19e9cab
|
||||
ff562c4c62faa7eaf112e12ab839e6bef4dcbdee42fa84d949e6857065432214
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
bbfc134f2121f301bbbcb0f0d596d7b3cc059455bba5ca78992e8bfa6630ce42
|
||||
ea1066f976a18f765057a217b9de7a6c9871da321c80e0f7d4ccac6642dd44dd
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
b7f45420859ce9540e0aae1fd803eee13529ef63d0a2f0b6ba9e43a5958eb457
|
||||
206f442d5360fc87b9e46ba5fdb7b7d0d4dc5ed550fd33181921c46463b5ea6f
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
041aa03873ff1d8133f181e86aab2ad3fda41e46503886754114f3abef3643da
|
||||
1d647b76ef93c768c23b63b93d666d96323d19cb5011865e1acb5a8d178e0c3e
|
||||
Бінарний файл не відображається.
+1
-1
@@ -1 +1 @@
|
||||
edcad61ab8e71cff2297edd9b902359d76ef04446bdfc42aae34420ced4d7f26
|
||||
b777e29256630e58a6e92ef95c67db8d091d0fc07af24e8b91b087eaac4d269c
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
aad3a25c3522fbff6f48c0c1e9de23b6d0d5361ba6658b744ad1590e9fdbe255
|
||||
b82d03052dd638871e278a691ad1ed09108ad4999678e6462780d686967eaf95
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
cfb432ea8943bf9b7e2f3ad3708df35260eebd04b3ac059c7643b378a35cd036
|
||||
eb2efa2d8f0f1fd3579de8a965679755e99ed87b06faf528c20c6a558ca0e56c
|
||||
@@ -101,3 +101,7 @@ title = "childdrop"
|
||||
[[contributes.commands]]
|
||||
id = "childtrap"
|
||||
title = "childtrap"
|
||||
|
||||
[[contributes.commands]]
|
||||
id = "patient"
|
||||
title = "patient"
|
||||
@@ -163,6 +163,28 @@ impl commands::Guest for Misbehave {
|
||||
Ok(Some(process::run_command(&cmd, None, None)?.stdout))
|
||||
}
|
||||
}
|
||||
// A task that keeps reporting is still working: the call may run
|
||||
// past the background budget it began with.
|
||||
"patient" => {
|
||||
let task = openidea::plugin::tasks::begin("waiting", false);
|
||||
let cmd = process::Command {
|
||||
program: "git".into(),
|
||||
args: vec!["hash-object".into(), "--stdin".into()],
|
||||
env: Vec::new(),
|
||||
};
|
||||
let child = process::start(&cmd, None)?;
|
||||
for step in 0..25 {
|
||||
task.report(step, Some(25), Some("waiting"));
|
||||
// Waiting blocks in the host for 100 ms: wall time passes
|
||||
// while the plugin itself is not running.
|
||||
let _ = child.wait(100);
|
||||
}
|
||||
// Let it finish on its own: no kill, no slow teardown.
|
||||
child.close_stdin()?;
|
||||
let _ = child.wait(5_000);
|
||||
task.report(25, Some(25), Some("done"));
|
||||
Ok(Some("still here".into()))
|
||||
}
|
||||
// `editor.write` is not granted: an error, not a trap.
|
||||
"insert" => {
|
||||
let editor = ctx.editor().ok_or_else(|| failed("no editor"))?;
|
||||
|
||||
Бінарний файл не відображається.
+1
-1
@@ -1 +1 @@
|
||||
82f53a3f36f965c76575a08609439e0bc9cea37f1aef7cc1671e9ec72a17f120
|
||||
f72d5a14faaab7fc51dcefe37ba434615ffe47482772339e4aeffa0127f5ce79
|
||||
Бінарний файл не відображається.
+1
-1
@@ -1 +1 @@
|
||||
a8d40f2224246e81e015d576a5fa70e83779af9fade614d61212b33fbb0961e9
|
||||
6d7583de2f1ce90bec0078e9d3e5fe63db2f1c0fa1e564dbe3c65327c1c6b045
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
e60bcf1e179f6485e14de3755907c93344ef3cdf8158f01bea84343858ba7434
|
||||
f9be5a80ddd63d623ec0e5a68e7f102c56955958874481cea52d4aabd0493dea
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
5cadc40061284bd5573f8323b02fb7ea7be18eb4323978b3f0b39337a9896774
|
||||
39163b3ce79c043c21fb2f87e980db4d2a3f0ae8c6678e1865875301416ba791
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
5377825f5801850d6ed7ec989f6e954fae477d81cd3ce0d5a2b8baeb9febcf74
|
||||
c060d8941dd7aba312c42ce5205bab91506be19450ac7b671381ce2088d44dfe
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
e1414e522a45066616475fae229c4dade82ba16eedef49aac8d4c014522a0684
|
||||
b6b4ebd96fb1a879947ba2b12b2497eb466150e7c44f60257cff869b2f1db941
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
5a50246a300a15c8b9e50457094442fe35f0efe1534feb6f5cb407e052404c07
|
||||
09863db73769c86bed14a4df0b0a4d480291aa1383172c406aba18a78e1d8989
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
61aaa8563701c6d4c147eaef87363ac0600c79fd9ef2ee8c8c1cc9c7e56794ed
|
||||
61485dc08ad905dbb2d8d211ef8be8a6e88292d2d41ba11c15be54c672eccba0
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
ab0a7b4daf59fda5938b10c42628bb141c94bc0d82464254a6b0157d74e98477
|
||||
1111db3957880758cf4ae2c34c95510846aef43c73ddeb03e901d5a10610544e
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
5813b46ce5ec12b9ca4bdfe61d49c63ed1af736238398a1c2e03ca7c3633469c
|
||||
8d0c17fb643bb7368877ae7cfe342286bc1c8a1fc8fdc00c7491beb5c24390fe
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
208cf58ff413f2ef75abfd0a4280d6e38393acf4e2d0a30f9c4d3294aa9ec82f
|
||||
ab15b403fb606ea226b491098f7b06335a03735d46a80a2d6e00cb042d201960
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
f83c2371ee5dd6c9d8d027ec3515fb7850141ac694d873ef0463a64ec6edcc9d
|
||||
ab64135fcdeee8579e9b9613b47cccd94f66ff46d7c3a0507320a1364ffe8921
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
f5baecb3f80efee4244bc096039ae7ac926c8bc73eb08fdfe5ecf81a4e2c38c9
|
||||
5b73dc19e676472cb94ec6c020d7fc6279b59aa8e8439b3840ece799035f1a2b
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
e4f62cf323d7186dcdc2972b0330086bc6279dcdc884d1997a84c1a589e739f8
|
||||
c6763b53f7d4228678827234dfd02e413bb604c867b4ead8cd185316e6482897
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
216af779424458d3fe4de470f2358f21ebc15d62be3d285f59cba19d61e59f3d
|
||||
1c735085dc8386adc94d4598eea8a2d5e582a98894f7742f83b97a9ddda7fb60
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
b2994bcb35737abbd001535308fcd4d3f0bab4cd61e580d8af1312451e760fe3
|
||||
1d0dcf3288ec08122b64e51fceb0055f3627531b7152a3cccfe7d44ddd4887c2
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
6d5d5b09fd48e9b48891a91b3dd13f9d0d2f1771685a549c683295370233ae17
|
||||
ae73ca009c7b36b3dd118a3a903c0132baf9c78baaceffe8d2a8a4ea8d182d1d
|
||||
Бінарний файл не відображається.
@@ -1 +1 @@
|
||||
5e6457d34c922284779cdcc42455ed1df9ed8b9245793134be566dcd3c8aab93
|
||||
730d2bc7b15d2598840ec8668555f89cdf77b800c2ce21df7601880c57be6b2b
|
||||
@@ -44,7 +44,9 @@ interface events {
|
||||
}
|
||||
|
||||
/// Long-running work with a progress indicator. While a task is open, the
|
||||
/// call that began it may run for the background budget (60 s) instead of 5 s.
|
||||
/// call that began it may run for the background budget (60 s) instead of 5 s,
|
||||
/// and each `report` or `is-cancelled` renews that budget: work that keeps
|
||||
/// saying it is alive is not cut off, while work that goes quiet is.
|
||||
interface tasks {
|
||||
resource task {
|
||||
/// `done` of `total` units (`none`: indeterminate), with a short status.
|
||||
|
||||
@@ -44,7 +44,9 @@ interface events {
|
||||
}
|
||||
|
||||
/// Long-running work with a progress indicator. While a task is open, the
|
||||
/// call that began it may run for the background budget (60 s) instead of 5 s.
|
||||
/// call that began it may run for the background budget (60 s) instead of 5 s,
|
||||
/// and each `report` or `is-cancelled` renews that budget: work that keeps
|
||||
/// saying it is alive is not cut off, while work that goes quiet is.
|
||||
interface tasks {
|
||||
resource task {
|
||||
/// `done` of `total` units (`none`: indeterminate), with a short status.
|
||||
|
||||
Reference in new issue
Заблокувати користувача