fix(graph): bound concurrency caps by the semaphore permit limit
Semaphore::new panics above tokio's MAX_PERMITS, so a fixed or templated map cap (or settings.max_concurrency) that large crashed the run instead of erroring. The validator rejects both at load, resolve_max_concurrency rejects every arm at run time, and the executor checks the graph setting before building its own semaphore, so validation mode makes no difference. Also corrects run_child_agent_with_graph_inputs' contract comment: inputs for a config-only agent are rejected, not ignored.
This commit is contained in:
4 files changed
+134
-3
No files matched your search
@@ -109,6 +109,13 @@ impl GraphExecutor {
|
||||
let max_iterations = graph.settings.max_loop_iterations;
|
||||
let graph_timeout = graph.settings.timeout.and_then(wall_clock);
|
||||
let max_concurrency = graph.settings.max_concurrency;
|
||||
if max_concurrency > Semaphore::MAX_PERMITS {
|
||||
bail!(
|
||||
"Graph '{}': settings.max_concurrency {max_concurrency} exceeds the runtime limit of {}",
|
||||
graph.name,
|
||||
Semaphore::MAX_PERMITS
|
||||
);
|
||||
}
|
||||
let graph = Arc::new(graph);
|
||||
let start = Instant::now();
|
||||
|
||||
@@ -1362,6 +1369,30 @@ nodes:
|
||||
assert!(err.contains("sleeper"), "error should name frontier: {err}");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn settings_max_concurrency_above_semaphore_limit_errors_instead_of_panicking() {
|
||||
let ws = TestWorkspace::new();
|
||||
let yaml = r#"
|
||||
name: oversized_cap_test
|
||||
start: done
|
||||
settings:
|
||||
validate_before_run: false
|
||||
nodes:
|
||||
done:
|
||||
type: end
|
||||
output: "done"
|
||||
"#;
|
||||
let mut graph: Graph = serde_yaml::from_str(yaml).unwrap();
|
||||
graph.settings.max_concurrency = Semaphore::MAX_PERMITS + 1;
|
||||
let mut ctx = make_ctx();
|
||||
let err = GraphExecutor::new(graph, &ws.dir)
|
||||
.execute(&mut ctx, create_abort_signal())
|
||||
.await
|
||||
.expect_err("an oversized cap is an error, not a panic");
|
||||
let msg = format!("{err:#}");
|
||||
assert!(msg.contains("exceeds the runtime limit of"), "{msg}");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn graph_timeout_zero_is_unbounded() {
|
||||
if !cmd_available("bash") {
|
||||
|
||||
Reference in new issue
Block a user