Skip to main content

Task Filtering and Sorting

async-inspect provides powerful filtering and sorting capabilities to help you find exactly the tasks you're looking for in large applications.

Overview

When debugging async applications, you often need to find specific tasks among thousands. The TaskFilter and sorting APIs let you:

  • Filter tasks by state (running, blocked, pending, completed, failed)
  • Search by name patterns
  • Filter by duration/age
  • Filter by poll count
  • Find child tasks of a specific parent
  • Sort results by various criteria

Using TaskFilter

The TaskFilter struct uses a builder pattern for constructing queries:

use async_inspect::prelude::*;
use std::time::Duration;

let inspector = Inspector::global();

// Find all running tasks with "fetch" in the name
let filter = TaskFilter::new()
.with_state(TaskState::Running)
.with_name_pattern("fetch");

let running_fetch_tasks = inspector.get_tasks_filtered(&filter);

Filter Criteria

By State

Filter tasks by their current execution state:

// Find all blocked tasks
let filter = TaskFilter::new()
.with_state(TaskState::Blocked { await_point: String::new() });

// Find running tasks
let filter = TaskFilter::new()
.with_state(TaskState::Running);

// Find completed tasks
let filter = TaskFilter::new()
.with_state(TaskState::Completed);

By Name Pattern

Search for tasks with names containing a substring (case-insensitive):

// Find all tasks with "database" in the name
let filter = TaskFilter::new()
.with_name_pattern("database");

// Find tasks related to HTTP
let filter = TaskFilter::new()
.with_name_pattern("http");

By Duration

Find tasks older or newer than a threshold:

use std::time::Duration;

// Find long-running tasks (older than 5 seconds)
let filter = TaskFilter::new()
.with_min_duration(Duration::from_secs(5));

// Find recently started tasks (less than 1 second old)
let filter = TaskFilter::new()
.with_max_duration(Duration::from_secs(1));

// Find tasks in a specific age range
let filter = TaskFilter::new()
.with_min_duration(Duration::from_secs(2))
.with_max_duration(Duration::from_secs(10));

By Poll Count

Filter based on how many times a task has been polled:

// Find tasks that have been polled many times (potential busy-wait)
let filter = TaskFilter::new()
.with_min_polls(1000);

// Find tasks that haven't been polled much
let filter = TaskFilter::new()
.with_max_polls(5);

By Parent Task

Find child tasks of a specific parent:

// Get all children of a specific task
let filter = TaskFilter::new()
.with_parent(parent_task_id);

// Get only root tasks (no parent)
let filter = TaskFilter::new()
.root_only();

Combining Filters

Filters can be combined for precise queries:

// Find long-running HTTP tasks that are currently blocked
let filter = TaskFilter::new()
.with_state(TaskState::Blocked { await_point: String::new() })
.with_name_pattern("http")
.with_min_duration(Duration::from_secs(10));

let stuck_http_tasks = inspector.get_tasks_filtered(&filter);

Sorting Results

Use get_tasks_sorted to get filtered results in a specific order:

use async_inspect::task::{TaskSortBy, SortDirection};

// Get blocked tasks sorted by age (oldest first)
let filter = TaskFilter::new()
.with_state(TaskState::Blocked { await_point: String::new() });

let tasks = inspector.get_tasks_sorted(
&filter,
TaskSortBy::Age,
SortDirection::Descending
);

Sort Options

Available sort criteria:

Sort ByDescription
TaskSortBy::IdSort by task ID (creation order)
TaskSortBy::NameSort alphabetically by name
TaskSortBy::AgeSort by task age
TaskSortBy::PollsSort by poll count
TaskSortBy::RunTimeSort by total CPU time
TaskSortBy::StateSort by state (Running, Blocked, Pending, Completed, Failed)

Sort directions:

  • SortDirection::Ascending - smallest/oldest first
  • SortDirection::Descending - largest/newest first

Convenience Methods

The Inspector provides convenience methods for common queries:

let inspector = Inspector::global();

// Get all currently running tasks
let running = inspector.get_running_tasks();

// Get all blocked tasks
let blocked = inspector.get_blocked_tasks();

// Get tasks older than a threshold
let long_running = inspector.get_long_running_tasks(Duration::from_secs(30));

// Get top-level tasks (no parent)
let roots = inspector.get_root_tasks();

// Get children of a specific task
let children = inspector.get_child_tasks(parent_id);

Using Filters Directly

You can also use TaskFilter directly on collections of tasks:

let all_tasks: Vec<TaskInfo> = get_tasks_somehow();

let filter = TaskFilter::new()
.with_state(TaskState::Running)
.with_min_duration(Duration::from_secs(1));

// Filter references
let filtered: Vec<&TaskInfo> = filter.filter(&all_tasks);

// Filter and clone
let filtered_owned: Vec<TaskInfo> = filter.filter_cloned(all_tasks);

Sorting Tasks Directly

Use the sort_tasks function on any mutable slice:

use async_inspect::task::{sort_tasks, TaskSortBy, SortDirection};

let mut tasks = inspector.get_all_tasks();
sort_tasks(&mut tasks, TaskSortBy::RunTime, SortDirection::Descending);

// Now tasks are sorted by CPU time, heaviest first
for task in tasks.iter().take(10) {
println!("Heavy task: {} ({:.2}s CPU)",
task.name,
task.total_run_time.as_secs_f64()
);
}

Practical Examples

Finding Stuck Tasks

// Tasks blocked for more than 30 seconds are likely stuck
let stuck = inspector.get_tasks_sorted(
&TaskFilter::new()
.with_state(TaskState::Blocked { await_point: String::new() })
.with_min_duration(Duration::from_secs(30)),
TaskSortBy::Age,
SortDirection::Descending
);

for task in stuck {
println!("[STUCK] {} blocked for {:.1}s",
task.name,
task.age().as_secs_f64()
);
}

Finding CPU-Heavy Tasks

// Tasks with high poll counts relative to age might be busy-waiting
let tasks = inspector.get_tasks_sorted(
&TaskFilter::new().with_min_polls(100),
TaskSortBy::Polls,
SortDirection::Descending
);

for task in tasks.iter().take(5) {
let polls_per_sec = task.poll_count as f64 / task.age().as_secs_f64();
println!("{}: {} polls ({:.1}/sec)",
task.name,
task.poll_count,
polls_per_sec
);
}

Analyzing Task Hierarchies

// Get root tasks and their immediate children
let roots = inspector.get_root_tasks();

for root in roots {
let children = inspector.get_child_tasks(root.id);
println!("{} ({} children)", root.name, children.len());

for child in children {
println!(" - {} [{}]", child.name, child.state);
}
}

Performance Notes

  • Filtering is performed on the current snapshot of tasks
  • Large filter operations hold a read lock briefly
  • For very large task sets, consider filtering early and often
  • The filter method returns references to avoid cloning when possible