Skip to main content

DagExecutor

Struct DagExecutor 

Source
pub struct DagExecutor { /* private fields */ }
Expand description

DAG executor that processes pipeline graphs

Executes scraping pipelines as directed acyclic graphs using petgraph. Independent branches are executed concurrently using tokio::spawn. Data from upstream nodes is passed as input to downstream nodes.

Implementations§

Source§

impl DagExecutor

Source

pub fn new() -> Self

Create a new DAG executor

§Example
use stygian_graph::domain::graph::DagExecutor;

let executor = DagExecutor::new();
Source

pub fn from_pipeline(pipeline: &Pipeline) -> Result<Self, StygianError>

Build a graph from a pipeline definition

§Errors

Returns GraphError::CycleDetected if the pipeline contains a cycle. Returns GraphError::NodeNotFound if an edge references an unknown node.

Source

pub async fn execute( &self, services: &HashMap<String, Arc<dyn ScrapingService>>, ) -> Result<Vec<NodeResult>, StygianError>

Execute the pipeline using the provided service registry.

Nodes are executed in topological order. Independent nodes at the same depth are spawned concurrently via tokio::spawn. The output of each node is available to all downstream nodes as their ServiceInput.params.

§Errors

Returns GraphError::ExecutionFailed if any node execution fails.

Source

pub fn node_count(&self) -> usize

Get the total number of nodes in the graph

§Example
use stygian_graph::domain::graph::{Pipeline, Node, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
assert_eq!(executor.node_count(), 2);
Source

pub fn edge_count(&self) -> usize

Get the total number of edges in the graph

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));
pipeline.add_edge(Edge::new("a", "b"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
assert_eq!(executor.edge_count(), 1);
Source

pub fn node_ids(&self) -> Vec<String>

Get all node IDs in the graph

§Example
use stygian_graph::domain::graph::{Pipeline, Node, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("fetch", "http", json!({})));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
assert!(executor.node_ids().contains(&"fetch".to_string()));
Source

pub fn get_node(&self, id: &str) -> Option<&Node>

Get a node by ID

§Example
use stygian_graph::domain::graph::{Pipeline, Node, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("fetch", "http", json!({})));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let node = executor.get_node("fetch");
assert!(node.is_some());
assert_eq!(node.unwrap().service, "http");
Source

pub fn predecessors(&self, id: &str) -> Vec<String>

Get the predecessors (upstream nodes) of a node

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));
pipeline.add_edge(Edge::new("a", "b"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let preds = executor.predecessors("b");
assert_eq!(preds, vec!["a".to_string()]);
Source

pub fn successors(&self, id: &str) -> Vec<String>

Get the successors (downstream nodes) of a node

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));
pipeline.add_edge(Edge::new("a", "b"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let succs = executor.successors("a");
assert_eq!(succs, vec!["b".to_string()]);
Source

pub fn topological_order(&self) -> Vec<String>

Get the topological order of nodes

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));
pipeline.add_edge(Edge::new("a", "b"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let order = executor.topological_order();
// "a" must appear before "b"
let a_pos = order.iter().position(|x| x == "a").unwrap();
let b_pos = order.iter().position(|x| x == "b").unwrap();
assert!(a_pos < b_pos);
Source

pub fn execution_waves(&self) -> Vec<ExecutionWave>

Get execution waves (groups of nodes that can run concurrently)

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));
pipeline.add_node(Node::new("c", "http", json!({})));
pipeline.add_edge(Edge::new("a", "c"));
pipeline.add_edge(Edge::new("b", "c"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let waves = executor.execution_waves();
// Wave 0 contains "a" and "b" (can run concurrently)
// Wave 1 contains "c" (depends on both)
assert_eq!(waves.len(), 2);
Source

pub fn node_info(&self, id: &str) -> Option<NodeInfo>

Get information about a specific node

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("fetch", "http", json!({"url": "https://example.com"})));
pipeline.add_node(Node::new("extract", "ai", json!({})));
pipeline.add_edge(Edge::new("fetch", "extract"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let info = executor.node_info("fetch").unwrap();
assert_eq!(info.service, "http");
assert_eq!(info.in_degree, 0);
assert_eq!(info.out_degree, 1);
Source

pub fn query_nodes(&self, query: &NodeQuery) -> Vec<NodeInfo>

Get all nodes matching a query

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use stygian_graph::domain::introspection::NodeQuery;
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("fetch1", "http", json!({})));
pipeline.add_node(Node::new("fetch2", "http", json!({})));
pipeline.add_node(Node::new("extract", "ai", json!({})));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let http_nodes = executor.query_nodes(&NodeQuery::by_service("http"));
assert_eq!(http_nodes.len(), 2);
Source

pub fn connectivity(&self) -> ConnectivityMetrics

Get connectivity metrics for the graph

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));
pipeline.add_edge(Edge::new("a", "b"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let metrics = executor.connectivity();
assert_eq!(metrics.root_nodes, vec!["a".to_string()]);
assert_eq!(metrics.leaf_nodes, vec!["b".to_string()]);
Source

pub fn critical_path(&self) -> CriticalPath

Get the critical path (longest path through the graph)

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));
pipeline.add_node(Node::new("c", "http", json!({})));
pipeline.add_edge(Edge::new("a", "b"));
pipeline.add_edge(Edge::new("b", "c"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let critical = executor.critical_path();
assert_eq!(critical.length, 3);
assert_eq!(critical.nodes, vec!["a", "b", "c"]);
Source

pub fn impact_analysis(&self, id: &str) -> ImpactAnalysis

Analyze the impact of changing a node

Returns all nodes that would be affected (upstream dependencies and downstream dependents, transitively).

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("a", "http", json!({})));
pipeline.add_node(Node::new("b", "http", json!({})));
pipeline.add_node(Node::new("c", "http", json!({})));
pipeline.add_edge(Edge::new("a", "b"));
pipeline.add_edge(Edge::new("b", "c"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let impact = executor.impact_analysis("b");
assert_eq!(impact.upstream, vec!["a".to_string()]);
assert_eq!(impact.downstream, vec!["c".to_string()]);
Source

pub fn snapshot(&self) -> GraphSnapshot

Get a complete snapshot of the graph for introspection

§Example
use stygian_graph::domain::graph::{Pipeline, Node, Edge, DagExecutor};
use serde_json::json;

let mut pipeline = Pipeline::new("test");
pipeline.add_node(Node::new("fetch", "http", json!({})));
pipeline.add_node(Node::new("extract", "ai", json!({})));
pipeline.add_edge(Edge::new("fetch", "extract"));

let executor = DagExecutor::from_pipeline(&pipeline).unwrap();
let snapshot = executor.snapshot();

assert_eq!(snapshot.node_count, 2);
assert_eq!(snapshot.edge_count, 1);

Trait Implementations§

Source§

impl Default for DagExecutor

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Paint for T
where T: ?Sized,

Source§

fn fg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the foreground set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like red() and green(), which have the same functionality but are pithier.

§Example

Set foreground color to white using fg():

use yansi::{Paint, Color};

painted.fg(Color::White);

Set foreground color to white using white().

use yansi::Paint;

painted.white();
Source§

fn primary(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Primary].

§Example
println!("{}", value.primary());
Source§

fn fixed(&self, color: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Fixed].

§Example
println!("{}", value.fixed(color));
Source§

fn rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the fg() set to [Color :: Rgb].

§Example
println!("{}", value.rgb(r, g, b));
Source§

fn black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Black].

§Example
println!("{}", value.black());
Source§

fn red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Red].

§Example
println!("{}", value.red());
Source§

fn green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Green].

§Example
println!("{}", value.green());
Source§

fn yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Yellow].

§Example
println!("{}", value.yellow());
Source§

fn blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Blue].

§Example
println!("{}", value.blue());
Source§

fn magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Magenta].

§Example
println!("{}", value.magenta());
Source§

fn cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: Cyan].

§Example
println!("{}", value.cyan());
Source§

fn white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: White].

§Example
println!("{}", value.white());
Source§

fn bright_black(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlack].

§Example
println!("{}", value.bright_black());
Source§

fn bright_red(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightRed].

§Example
println!("{}", value.bright_red());
Source§

fn bright_green(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightGreen].

§Example
println!("{}", value.bright_green());
Source§

fn bright_yellow(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightYellow].

§Example
println!("{}", value.bright_yellow());
Source§

fn bright_blue(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightBlue].

§Example
println!("{}", value.bright_blue());
Source§

fn bright_magenta(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.bright_magenta());
Source§

fn bright_cyan(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightCyan].

§Example
println!("{}", value.bright_cyan());
Source§

fn bright_white(&self) -> Painted<&T>

Returns self with the fg() set to [Color :: BrightWhite].

§Example
println!("{}", value.bright_white());
Source§

fn bg(&self, value: Color) -> Painted<&T>

Returns a styled value derived from self with the background set to value.

This method should be used rarely. Instead, prefer to use color-specific builder methods like on_red() and on_green(), which have the same functionality but are pithier.

§Example

Set background color to red using fg():

use yansi::{Paint, Color};

painted.bg(Color::Red);

Set background color to red using on_red().

use yansi::Paint;

painted.on_red();
Source§

fn on_primary(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Primary].

§Example
println!("{}", value.on_primary());
Source§

fn on_fixed(&self, color: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Fixed].

§Example
println!("{}", value.on_fixed(color));
Source§

fn on_rgb(&self, r: u8, g: u8, b: u8) -> Painted<&T>

Returns self with the bg() set to [Color :: Rgb].

§Example
println!("{}", value.on_rgb(r, g, b));
Source§

fn on_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Black].

§Example
println!("{}", value.on_black());
Source§

fn on_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Red].

§Example
println!("{}", value.on_red());
Source§

fn on_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Green].

§Example
println!("{}", value.on_green());
Source§

fn on_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Yellow].

§Example
println!("{}", value.on_yellow());
Source§

fn on_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Blue].

§Example
println!("{}", value.on_blue());
Source§

fn on_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Magenta].

§Example
println!("{}", value.on_magenta());
Source§

fn on_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: Cyan].

§Example
println!("{}", value.on_cyan());
Source§

fn on_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: White].

§Example
println!("{}", value.on_white());
Source§

fn on_bright_black(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlack].

§Example
println!("{}", value.on_bright_black());
Source§

fn on_bright_red(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightRed].

§Example
println!("{}", value.on_bright_red());
Source§

fn on_bright_green(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightGreen].

§Example
println!("{}", value.on_bright_green());
Source§

fn on_bright_yellow(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightYellow].

§Example
println!("{}", value.on_bright_yellow());
Source§

fn on_bright_blue(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightBlue].

§Example
println!("{}", value.on_bright_blue());
Source§

fn on_bright_magenta(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightMagenta].

§Example
println!("{}", value.on_bright_magenta());
Source§

fn on_bright_cyan(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightCyan].

§Example
println!("{}", value.on_bright_cyan());
Source§

fn on_bright_white(&self) -> Painted<&T>

Returns self with the bg() set to [Color :: BrightWhite].

§Example
println!("{}", value.on_bright_white());
Source§

fn attr(&self, value: Attribute) -> Painted<&T>

Enables the styling Attribute value.

This method should be used rarely. Instead, prefer to use attribute-specific builder methods like bold() and underline(), which have the same functionality but are pithier.

§Example

Make text bold using attr():

use yansi::{Paint, Attribute};

painted.attr(Attribute::Bold);

Make text bold using using bold().

use yansi::Paint;

painted.bold();
Source§

fn bold(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Bold].

§Example
println!("{}", value.bold());
Source§

fn dim(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Dim].

§Example
println!("{}", value.dim());
Source§

fn italic(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Italic].

§Example
println!("{}", value.italic());
Source§

fn underline(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Underline].

§Example
println!("{}", value.underline());

Returns self with the attr() set to [Attribute :: Blink].

§Example
println!("{}", value.blink());

Returns self with the attr() set to [Attribute :: RapidBlink].

§Example
println!("{}", value.rapid_blink());
Source§

fn invert(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Invert].

§Example
println!("{}", value.invert());
Source§

fn conceal(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Conceal].

§Example
println!("{}", value.conceal());
Source§

fn strike(&self) -> Painted<&T>

Returns self with the attr() set to [Attribute :: Strike].

§Example
println!("{}", value.strike());
Source§

fn quirk(&self, value: Quirk) -> Painted<&T>

Enables the yansi Quirk value.

This method should be used rarely. Instead, prefer to use quirk-specific builder methods like mask() and wrap(), which have the same functionality but are pithier.

§Example

Enable wrapping using .quirk():

use yansi::{Paint, Quirk};

painted.quirk(Quirk::Wrap);

Enable wrapping using wrap().

use yansi::Paint;

painted.wrap();
Source§

fn mask(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Mask].

§Example
println!("{}", value.mask());
Source§

fn wrap(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Wrap].

§Example
println!("{}", value.wrap());
Source§

fn linger(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Linger].

§Example
println!("{}", value.linger());
Source§

fn clear(&self) -> Painted<&T>

👎Deprecated since 1.0.1:

renamed to resetting() due to conflicts with Vec::clear(). The clear() method will be removed in a future release.

Returns self with the quirk() set to [Quirk :: Clear].

§Example
println!("{}", value.clear());
Source§

fn resetting(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Resetting].

§Example
println!("{}", value.resetting());
Source§

fn bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: Bright].

§Example
println!("{}", value.bright());
Source§

fn on_bright(&self) -> Painted<&T>

Returns self with the quirk() set to [Quirk :: OnBright].

§Example
println!("{}", value.on_bright());
Source§

fn whenever(&self, value: Condition) -> Painted<&T>

Conditionally enable styling based on whether the Condition value applies. Replaces any previous condition.

See the crate level docs for more details.

§Example

Enable styling painted only when both stdout and stderr are TTYs:

use yansi::{Paint, Condition};

painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);
Source§

fn new(self) -> Painted<Self>
where Self: Sized,

Create a new Painted with a default Style. Read more
Source§

fn paint<S>(&self, style: S) -> Painted<&Self>
where S: Into<Style>,

Apply a style wholesale to self. Any previous style is replaced. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more