pub struct FlowRunner { /* private fields */ }
Expand description
High-level helper that orchestrates the common load → execute → save pattern.
FlowRunner
provides a convenient wrapper around the lower-level graph execution
API. It automatically handles session loading, execution, and persistence.
§When to Use FlowRunner
- Web services: Execute one step per HTTP request
- Interactive applications: Step-by-step workflow progression
- Simple demos: Minimal boilerplate for common use cases
§Performance
FlowRunner
is lightweight and efficient:
- Creation cost: ~2 pointer copies (negligible)
- Memory overhead: 16 bytes (2 ×
Arc<T>
) - Runtime cost: Identical to manual approach
§Examples
§Basic Usage
use graph_flow::{FlowRunner, Graph, InMemorySessionStorage, Session, SessionStorage};
use std::sync::Arc;
let graph = Arc::new(Graph::new("my_workflow"));
let storage = Arc::new(InMemorySessionStorage::new());
let runner = FlowRunner::new(graph, storage.clone());
// Create a session first
let session = Session::new_from_task("session_id".to_string(), "start_task");
storage.save(session).await?;
// Execute workflow step
let result = runner.run("session_id").await?;
println!("Response: {:?}", result.response);
§Shared Runner Pattern (Recommended for Web Services)
use graph_flow::FlowRunner;
use std::sync::Arc;
// Application state
struct AppState {
flow_runner: Arc<FlowRunner>,
}
impl AppState {
fn new(runner: FlowRunner) -> Self {
Self {
flow_runner: Arc::new(runner),
}
}
}
// Request handler
async fn handle_request(
state: Arc<AppState>,
session_id: String,
) -> Result<String, Box<dyn std::error::Error>> {
let result = state.flow_runner.run(&session_id).await?;
Ok(result.response.unwrap_or_default())
}
Implementations§
Source§impl FlowRunner
impl FlowRunner
Sourcepub fn new(graph: Arc<Graph>, storage: Arc<dyn SessionStorage>) -> Self
pub fn new(graph: Arc<Graph>, storage: Arc<dyn SessionStorage>) -> Self
Create a new FlowRunner
from an Arc<Graph>
and any SessionStorage
implementation.
§Parameters
graph
- The workflow graph to executestorage
- Storage backend for session persistence
§Examples
use graph_flow::{FlowRunner, Graph, InMemorySessionStorage};
use std::sync::Arc;
let graph = Arc::new(Graph::new("my_workflow"));
let storage = Arc::new(InMemorySessionStorage::new());
let runner = FlowRunner::new(graph, storage);
§With PostgreSQL Storage
use graph_flow::{FlowRunner, Graph, PostgresSessionStorage};
use std::sync::Arc;
let graph = Arc::new(Graph::new("my_workflow"));
let storage = Arc::new(
PostgresSessionStorage::connect("postgresql://localhost/mydb").await?
);
let runner = FlowRunner::new(graph, storage);
Sourcepub async fn run(&self, session_id: &str) -> Result<ExecutionResult>
pub async fn run(&self, session_id: &str) -> Result<ExecutionResult>
Execute exactly one task for the given session_id
and persist the updated session.
This method:
- Loads the session from storage
- Executes the current task
- Saves the updated session back to storage
- Returns the execution result
§Parameters
session_id
- Unique identifier for the session to execute
§Returns
Returns the same ExecutionResult
that Graph::execute_session
does, so callers can
inspect the assistant’s response and the status (WaitingForInput
, Completed
, etc.).
§Errors
Returns an error if:
- The session doesn’t exist
- Task execution fails
- Storage operations fail
§Examples
§Basic Execution
let result = runner.run("test_session").await?;
match result.status {
graph_flow::ExecutionStatus::Completed => {
println!("Workflow completed: {:?}", result.response);
}
graph_flow::ExecutionStatus::WaitingForInput => {
println!("Waiting for user input: {:?}", result.response);
}
graph_flow::ExecutionStatus::Paused { next_task_id, reason } => {
println!("Paused, next task: {}, reason: {}", next_task_id, reason);
}
graph_flow::ExecutionStatus::Error(e) => {
eprintln!("Error: {}", e);
}
}
§Interactive Loop
loop {
let result = runner.run("session_id").await?;
match result.status {
ExecutionStatus::Completed => break,
ExecutionStatus::WaitingForInput => {
// Get user input and update context
// Then continue loop
break; // For demo
}
ExecutionStatus::Paused { .. } => {
// Continue to next step
continue;
}
ExecutionStatus::Error(e) => {
eprintln!("Error: {}", e);
break;
}
}
}
§Error Handling
match runner.run("nonexistent_session").await {
Ok(result) => {
println!("Success: {:?}", result.response);
}
Err(GraphError::SessionNotFound(session_id)) => {
eprintln!("Session not found: {}", session_id);
}
Err(GraphError::TaskExecutionFailed(msg)) => {
eprintln!("Task failed: {}", msg);
}
Err(e) => {
eprintln!("Other error: {}", e);
}
}
Trait Implementations§
Source§impl Clone for FlowRunner
impl Clone for FlowRunner
Source§fn clone(&self) -> FlowRunner
fn clone(&self) -> FlowRunner
Returns a duplicate of the value. Read more
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source
. Read moreAuto Trait Implementations§
impl Freeze for FlowRunner
impl !RefUnwindSafe for FlowRunner
impl Send for FlowRunner
impl Sync for FlowRunner
impl Unpin for FlowRunner
impl !UnwindSafe for FlowRunner
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more