Review fixes for SESSION-02. An expired caller deadline was becoming a failed epoch without the ipc-v1 section 6 resolution. That procedure existed and was correct and had exactly one caller, a test injection, so the deadline this slice introduced bypassed it and a merely slow participant lost its epoch. Deadlines is now the two-stage shape section 6 describes -- a probe, then a bounded resolve budget and attempt count -- call_owned returns a typed CallOutcome so an expiry is distinguishable from a refusal, and Prepare, Commit, Advance and the lifecycle calls all query the same request id against the same incarnation before the epoch can fail. This is also step-v1 section 7's Advance row, which was imperative about it. The coordinator peak-RSS column was measuring the measuring process. VmHWM never falls and every row shared one process, so the column was cumulative and the mode ranking reversed when the rows were reordered. Each row now runs in a measure-row child of its own. The corrected numbers say the opposite of what the first report claimed: the coordinator's own peak is roughly flat across the modes and lowest in process mode, and the cost of the split is the children. workers-v1 section 2 bounded Agent.Initialize's workerThreads by "within launcher allocation" and named no wire for it. Dated amendment: HelloResult.limits gains workerThreads, the worker reports what its launcher gave it, and the launcher refuses one that disagrees. The schema set, the shared fixtures and the TypeScript package move together; contractDigest changes, which ipc-v1 section 4 provides for. Also: the stale-epoch row now reaches the stale-epoch path against a live agent process and asserts exact codes on both halves; the router-restart row asserts the handle drop it claimed; frames are counted from the behaviour trace instead of calculated; the README says which suites run over which transports; bootstrap is fence-guarded; the shutdown reason is an Id rather than a silent fallback; and agent_mutations returns None rather than zero where the counter lives in another process.
75 lines
2.8 KiB
Rust
75 lines
2.8 KiB
Rust
//! The same synthetic session in all three execution modes, printing the one behaviour trace
|
|
//! they agree on.
|
|
//!
|
|
//! ```sh
|
|
//! cargo run -p fly-session --example processes
|
|
//! ```
|
|
//!
|
|
//! The separate-process run starts one agent process per fly and one environment process
|
|
//! through this crate's own binary, so it needs that binary built:
|
|
//!
|
|
//! ```sh
|
|
//! cargo build -p fly-session --bin fly-session
|
|
//! ```
|
|
|
|
use fly_session::harness::{ExecutionMode, HarnessConfig, SessionHarness, Via};
|
|
use fly_session::launcher::default_worker_program;
|
|
|
|
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let program = default_worker_program();
|
|
println!("worker program: {}", program.display());
|
|
let mut agreed: Option<Vec<String>> = None;
|
|
|
|
for mode in ExecutionMode::all() {
|
|
let dir = tempfile::tempdir()?;
|
|
let config = HarnessConfig { mode, ..HarnessConfig::default() };
|
|
println!(
|
|
"\n=== {} : {} threads for {} participants plus the coordinator",
|
|
mode.label(),
|
|
config.budget()?.total(),
|
|
config.agents.len() + 1
|
|
);
|
|
let mut harness = SessionHarness::start(Via::Unix, dir.path(), config).await?;
|
|
harness.coordinator.bootstrap().await?;
|
|
let reports = harness.coordinator.run(3).await?;
|
|
for report in &reports {
|
|
println!(" committed boundary {}", report.boundary);
|
|
}
|
|
for (worker_id, status) in harness.launcher.health_check_all().await {
|
|
match status {
|
|
Ok(status) => println!(
|
|
" {worker_id}: {:?}, progress {}",
|
|
status.state, status.progress_counter
|
|
),
|
|
Err(e) => println!(" {worker_id}: unhealthy: {e}"),
|
|
}
|
|
}
|
|
let behaviour = harness.coordinator.trace.behavior();
|
|
match &agreed {
|
|
None => {
|
|
println!(" behaviour trace, {} transitions:", behaviour.len());
|
|
for line in &behaviour {
|
|
println!(" {line}");
|
|
}
|
|
agreed = Some(behaviour);
|
|
}
|
|
Some(first) => {
|
|
assert_eq!(
|
|
&behaviour, first,
|
|
"{} produced a different behaviour trace",
|
|
mode.label()
|
|
);
|
|
println!(" behaviour trace: identical to the first run");
|
|
}
|
|
}
|
|
let reaped = harness.launcher.reap_all(&fly_session::types::id("example")).await;
|
|
for (worker_id, outcome) in reaped {
|
|
println!(" reaped {worker_id}: {outcome:?}");
|
|
}
|
|
harness.shutdown().await;
|
|
drop(dir);
|
|
}
|
|
println!("\nall three execution modes produced one behaviour trace");
|
|
Ok(())
|
|
}
|