# execute jobs
Once you build a job graph, it can be executed by a `Runner`.
```rust
# (|| {
use crate::willdo::execution::Runner as _;
let graph = willdo::graph::Graph::builder().build()?;
let runner = willdo::execution::runner::simple::Simple;
let goals = ["bake".into()];
let events = runner.run(graph, &goals);
# Ok::<(),willdo::graph::BuildError>(()) })().expect("build");
```
This will produce a `Stream` of (`JobId`,`Progress`) events, consuming the graph.
It can also mutably borrow the graph so you can access it when done:
```rust
# (|| {
# use crate::willdo::execution::Runner as _;
let mut graph = willdo::graph::Graph::builder().build()?;
let runner = willdo::execution::Simple;
let goals = ["bake".into()];
let events = runner.run(&mut graph, &goals);
drop(events); // release the reference
println!("{graph}");
# Ok::<(),willdo::graph::BuildError>(()) })().expect("build");
```
Pick the jobs to run with `goals`. Passing an empty slice will run all top level jobs found.
Note that the `"bake"` goal does not exist in the graph and this is not an error to ask for missing jobs.
You can check that a desired job exists by examining the graph first.
Then you can process the events:
```rust
# use futures_lite::stream::StreamExt as _;
# async move {
# use crate::willdo::execution::Runner as _;
# let mut graph = willdo::graph::Graph::builder().build().expect("build");
# let runner = willdo::execution::Simple;
# let goals = ["bake".into()];
# let mut events = runner.run(&mut graph, &goals);
while let Some((id, progress)) = events.next().await {
println!("{id}: {progress:?}");
}
# };
```