flybrain/services/flysim/crates/fly-session/examples/processes.rs
acamilo 7b7ebcdf28 session: parallel processes, a launcher and the fault behaviour
SESSION-02: one agent process per fly and one environment process under
the coordinator over the Unix-socket transport, compared against the
in-process composition and a dedicated-thread variant. The mode is the
only thing that changes; the composition, the coordinator, the workers
and the router are the same code in all three.

The launcher is the configured supervisor. It owns a total thread budget
with one allocation per participant, refused as BUSY before anything
starts when the total cannot cover it; the configured client, service,
worker and port identities, proved in Worker.Hello before the
coordinator pins a registration; Worker.Status health on the
supervisor's own monotonic clock at the ipc-v1 section 6 budgets; and
reaping, where Worker.Shutdown is the request and the operating system
is the guarantee.

The worker executable is a subcommand of this crate's one binary, which
is what implementation.md section 2 allows in place of a separate
worker crate.

The coordinator's fault behaviour: every failure names the participant
it is attributed to, every domain call has a caller-side deadline so a
dead participant is a diagnosed outcome rather than a hang, and failing
fences the epoch -- the boundary stops, the handles drop, and no further
transition or publication is allowed. Agent.Initialize now carries the
launcher's allocation, and an agent refuses one asking for more.

tests/processes.rs proves every acceptance bullet once per execution
mode, and the two section 4 rows SESSION-01 could not reach in one
process: a router restart during a world advance, and an old worker's
reply after a restart. measure compares the three modes at one, two and
four agents; its table is in the crate README, and it is not a capacity
claim.
2026-09-22 14:33:25 +00:00

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("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(())
}