Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

What is Crossflow?

Crossflow is a general-purpose Rust library for reactive and async programming. It simplifies the challenges of implementing highly async software systems that may have parallel activities with interdependencies, conditional branching, and/or cycles. Its specialty is creating event-driven multi-agent state machines.

Implemented in Rust on the Bevy ECS, crossflow has high performance and guaranteed-safe parallelism, making it suitable for highly responsive low-level state machines, just as well as high-level visually programmed device orchestrators.

Services

The basic unit of work in crossflow is encapsulated by a service. Services take an input message and eventually yield an output message—perhaps immediately or perhaps after some long-running routine has finished.

apple-pie-service

In crossflow services are defined by Bevy Systems that take an input and produce an output. As Bevy Systems, the crossflow services can integrate into an application by interacting with the Bevy World through entities, components, and resources of Bevy’s ECS. This allows services to have enormous versatility in how they are implemented, while still being highly parallelizable, memory-safe, and efficient.

A service can be executed by sending it a request at any time using this line of code:

#![allow(unused)]
fn main() {
let outcome = commands.request(input, service).outcome();
}

This line is non-blocking, meaning the service will be executed concurrently with the rest of the application’s activity. The outcome is a receiver that can be polled—or better yet awaited in an async context—until the service has sent its response or has been cancelled.

Workflows

Best practice when creating complex systems is to encapsulate services into the simplest possible building blocks and assemble those blocks into increasingly sophisticated structures. This is where workflows come in.

sense-think-act

Workflows allow you to assemble services into a directed graph—cycles are allowed—that form a more complex behavior, feeding the output of each service as input to another service. Workflows are excellent for defining state machines that have async state transitions or that have lots of parallel activity that needs to be managed and synchronized.

When you create a workflow you will ultimately be creating yet another service that can be treated exactly the same as a service created using a Bevy System. This workflow-based service can even be used as a node inside of another workflow. In other words, you can build hierarchical workflows.

Execution

You can run as many service requests as you want at the same time for as many services or workflows as you want, including making multiple simultaneous requests for the same service or workflow. Each time request is called, a new “session” will be spawned that executes the workflow or service independently from any other that is running. However, if any of the services or workflows interact with “the world” (either the Bevy World, the actual physical world, or some external resource) then those services or workflows may indirectly interact with each other.

Tip

Check out the live web demo to get a sense for what a workflow might look like.

Try passing in [20, 30] as the request message and run the workflow to see the message get split and calculated.

Getting Started

To get you started with crossflow, the next chapter will teach you how to spawn a basic service. After that you will see how to run a service, then how to assemble services into a workflow (which is itself a service) and execute it.

To learn the fundamental concepts around what a “workflow” is in the crossflow library, see the Introduction to Workflows chapter.