# How Trio Orchestrates Asynchronous Tasks in Holehe

> Learn how Trio orchestrates async tasks in Holehe. Discover structured concurrency, automatic cancellation, and real-time progress tracking for efficient site-checking operations.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: internals
- Published: 2026-09-09

---

**Holehe leverages the Trio library to execute concurrent site-checking operations with structured concurrency, automatic cancellation, and real-time progress tracking.**

The open-source OSINT tool Holehe (megadose/holehe) checks email address registrations across hundreds of websites using asynchronous HTTP requests. By implementing Trio as its async runtime, Holehe manages these I/O-bound tasks efficiently while maintaining clean error handling and providing users with live progress feedback. This article examines the specific mechanisms—from nurseries to instruments—that enable Trio to orchestrate Holehe's parallel website enumeration.

## Trio as the Async Runtime

Holehe's entry point in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) initializes the async event loop using Trio's high-level API. The `main()` function invokes `trio.run(maincore)` at lines 33–34, which creates the event loop and drives the primary coroutine until completion.

```python

# From holehe/core.py (lines 33-34)

trio.run(maincore)

```

This approach provides a structured entry point that handles setup and teardown automatically. When `maincore` completes or raises an exception, Trio cleans up the event loop and propagates the result back to the synchronous caller.

## Structured Concurrency with Nurseries

Inside `maincore`, Holehe achieves parallelism through Trio's **nursery** abstraction. The code opens a nursery context manager at lines 18–21, launching a separate task for each site-checking module using `nursery.start_soon()`.

```python

# From holehe/core.py (lines 18-21)

async with trio.open_nursery() as nursery:
    for module in modules:
        nursery.start_soon(launch_module, module, email, client, out)

```

The nursery guarantees **structured concurrency**: all spawned tasks must complete before the `async with` block exits. This prevents orphaned HTTP requests and ensures that the program cannot accidentally leave background tasks running after the main logic finishes.

## Progress Tracking via Trio Instruments

To provide live feedback without cluttering business logic, Holehe implements a custom `TrioProgress` instrument in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py). This class subclasses `trio.abc.Instrument` and wraps a `tqdm` progress bar.

The instrument registers with Trio's low-level API before the nursery opens:

```python

# From holehe/instruments.py (lines 4-10)

instrument = TrioProgress(len(modules))
trio.lowlevel.add_instrument(instrument)

# ... run the main work ...

trio.lowlevel.remove_instrument(instrument)

```

The `TrioProgress.task_exited` hook (lines 8–10) detects when a `launch_module` task finishes and increments the progress bar:

```python
def task_exited(self, task):
    if task.name.endswith("launch_module"):
        self.bar.update(1)

```

This instrumentation pattern separates instrumentation concerns from the core site-checking logic, allowing the progress indicator to update automatically as the nursery manages task lifecycle events.

## Error Handling and Task Cancellation

Each `launch_module` coroutine executes the specific site-checking function (e.g., `amazon(email, client, out)`) and handles exceptions gracefully. In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) at lines 66–78, the code catches errors and appends placeholder results to the output list rather than crashing the entire nursery.

Because Trio nurseries propagate cancellation automatically, if one module encounters an unexpected error or the user interrupts the process, Trio cancels all running tasks within that nursery scope. This prevents resource leaks and ensures that in-flight HTTP requests through `httpx.AsyncClient` are cleaned up properly.

## Key Implementation Features

Holehe utilizes four critical Trio capabilities to manage its async workload:

| Feature | Implementation Details |
|---------|----------------------|
| **Structured Concurrency** | `async with trio.open_nursery()` ensures all site checks complete together before the program proceeds. |
| **Task Cancellation** | Nurseries automatically propagate cancellation to sibling tasks when one fails, preventing orphaned connections. |
| **Instrument API** | `TrioProgress` hooks into task lifecycle events to drive the progress bar without modifying site-checking code. |
| **Simple Async Primitives** | `await module(email, client, out)` executes I/O-heavy HTTP checks using `httpx.AsyncClient` within Trio's event loop. |

## Practical Code Examples

You can run Holehe's async core directly using Trio's entry point:

```python
import trio
from holehe.core import maincore

# Execute the full async pipeline (equivalent to CLI entry point)

trio.run(maincore)

```

To implement similar progress tracking in your own Trio applications, subclass `trio.abc.Instrument`:

```python
import trio
from tqdm import tqdm

class LogProgress(trio.abc.Instrument):
    def __init__(self, total):
        self.bar = tqdm(total=total)

    def task_exited(self, task):
        # Increment progress when any task finishes

        self.bar.update(1)

# Register before launching concurrent work

instrument = LogProgress(total=5)
trio.lowlevel.add_instrument(instrument)

async def demo():
    async with trio.open_nursery() as n:
        for i in range(5):
            n.start_soon(trio.sleep, 0.1)  # Simulated async work

trio.run(demo)  # Progress bar advances 5 steps

```

## Summary

- **Trio Runtime**: Holehe uses `trio.run(maincore)` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) to initialize the async event loop and drive the primary coroutine.
- **Nursery Concurrency**: The `async with trio.open_nursery()` block at lines 18–21 launches parallel site checks via `nursery.start_soon()`, ensuring structured concurrency.
- **Custom Instruments**: `TrioProgress` in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) implements `trio.abc.Instrument` to update a `tqdm` progress bar through the `task_exited` lifecycle hook.
- **Automatic Cleanup**: Trio's nursery model propagates cancellation across all tasks, preventing orphaned HTTP requests when errors occur or processing completes.

## Frequently Asked Questions

### How does Holehe handle multiple concurrent HTTP requests without blocking?

Holehe uses Trio's nursery mechanism to spawn concurrent tasks. Each site-checking module runs as a separate task within `trio.open_nursery()`, allowing `httpx.AsyncClient` to perform non-blocking I/O while Trio manages the event loop.

### What happens if one site-checking module crashes in Holehe?

According to the source code in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) (lines 66–78), individual exceptions are caught within `launch_module` and converted to placeholder results. However, if an unexpected error propagates out of the nursery, Trio cancels all sibling tasks automatically, ensuring no orphaned HTTP requests remain.

### Can I use Holehe's progress tracking pattern in my own Trio applications?

Yes. The `TrioProgress` class in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) demonstrates how to subclass `trio.abc.Instrument` and implement `task_exited()` to react to task completion. Register your instrument with `trio.lowlevel.add_instrument()` before opening your nursery, and remove it afterward to avoid memory leaks.

### Why does Holehe choose Trio over asyncio or other async libraries?

Trio provides structured concurrency through nurseries, which guarantee that all spawned tasks complete before exiting a scope. This eliminates a class of concurrency bugs common in traditional asyncio programs. Holehe leverages this to manage hundreds of site checks safely while maintaining clean cancellation semantics and providing hooks for progress instrumentation.