Skip to main content

TaskGraph

Struct TaskGraph 

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

A directed acyclic graph (DAG) of TaskNodes.

§Invariants (enforced by add_task)

  1. Every node ID is unique.
  2. Every referenced dependency ID must already exist in the graph.
  3. No cycles — checked by running Kahn’s algorithm after every insert.

§Storage

Nodes are stored in a Vec (preserving insertion order) together with an ID→index map for O(1) lookups. The dependency lists are the adjacency representation; we build a reverse map on demand for algorithms that need it.

Implementations§

Source§

impl TaskGraph

Source

pub fn new() -> Self

Create an empty graph.

Source

pub fn add_task(&mut self, node: TaskNode) -> Result<()>

Add a new task node to the graph.

§Errors
  • Duplicate ID
  • Unknown dependency ID (must be added before the dependent node)
  • Cycle detection (added after all edges are registered)
Source

pub fn mark_running(&mut self, id: &str) -> Result<()>

Mark a task as Running.

§Errors
  • Task ID not found
  • Task is not in Pending state (can only start from Pending)
Source

pub fn mark_completed(&mut self, id: &str, result: AgentResult) -> Result<()>

Mark a task as successfully Completed and store its result.

§Errors
  • Task ID not found
Source

pub fn mark_failed(&mut self, id: &str, error: String) -> Result<()>

Mark a task as Failed.

The retries counter in the Failed variant is initialised to 0 if the task was previously Pending/Running, or incremented if it was already Failed (i.e. this is a retry that also failed).

§Errors
  • Task ID not found
Source

pub fn mark_cancelled(&mut self, id: &str) -> Result<()>

Mark a task as Cancelled.

§Errors
  • Task ID not found
Source

pub fn reset_for_retry(&mut self, id: &str) -> Result<()>

Reset a failed task back to Pending so it can be retried.

The executor calls this before re-queueing a Failed task.

§Errors
  • Task ID not found
  • Task is not in Failed state
Source

pub fn nodes(&self) -> impl Iterator<Item = &TaskNode>

Returns an iterator over all nodes in insertion order.

Source

pub fn len(&self) -> usize

Returns the number of nodes in the graph.

Source

pub fn is_empty(&self) -> bool

Returns true if the graph has no nodes.

Source

pub fn get(&self, id: &str) -> Option<&TaskNode>

Look up a node by ID. Returns None if not found.

Source

pub fn topological_sort(&self) -> Result<Vec<String>>

Topological sort using Kahn’s BFS algorithm.

Returns a linearised ordering of all task IDs such that every task appears after all of its dependencies. If multiple orderings are valid (i.e. there are independent tasks), the result is deterministic but arbitrary — use compute_waves to get explicit parallel batches.

§Errors

Returns an error if a cycle is detected (should not happen if nodes were added via add_task, which validates on insert).

Source

pub fn compute_waves(&self) -> Result<Vec<Vec<String>>>

Compute parallel execution waves.

A “wave” is a group of tasks that:

  1. Have all dependencies in earlier waves (so they can run immediately once the previous wave finishes), AND
  2. Are independent of each other within the wave (no edge between them).

This is the critical function for “完全安全托管” — the executor uses these waves to maximise concurrency: it runs all tasks in wave 0 in parallel, waits for all to complete, then runs wave 1 in parallel, etc.

Algorithm: assign each node a “wave number” = 1 + max(wave numbers of its dependencies). Nodes with no dependencies get wave 0. This is a standard “longest path in a DAG” computation.

§Returns

A Vec<Vec<String>> where:

  • result[0] = IDs of tasks that can run immediately (no deps)
  • result[1] = IDs of tasks whose deps are all in result[0]
  • …and so on
§Errors

Propagates any cycle error from topological_sort.

Source

pub fn next_ready(&self) -> Vec<&TaskNode>

Returns all tasks that are currently eligible to run.

A task is “ready” when:

  • Its status is Pending, AND
  • Every task in depends_on has status Completed.

The executor calls this after each task completes to find new tasks to dispatch.

Source

pub fn is_finished(&self) -> bool

Returns true when every node in the graph is in a terminal state.

The executor uses this as its loop termination condition.

Source

pub fn is_all_completed(&self) -> bool

Returns true when every node has status Completed.

Source

pub fn status_counts(&self) -> (usize, usize, usize, usize, usize)

Counts tasks by status category (for progress display).

Returns (pending, running, completed, failed, cancelled).

Source§

impl TaskGraph

Source

pub fn rebuild_index(&mut self)

Rebuild the id_to_index map after deserialisation.

serde skips id_to_index (marked #[serde(skip)]) so we must rebuild it when loading a saved graph. Call this immediately after deserialising:

let mut graph: TaskGraph = serde_json::from_str(&json)?;
graph.rebuild_index();

Trait Implementations§

Source§

impl Debug for TaskGraph

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for TaskGraph

Source§

fn default() -> TaskGraph

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

impl<'de> Deserialize<'de> for TaskGraph

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for TaskGraph

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. 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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. 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, 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
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,