# How Holehe's Concurrency Model Works with Trio: Structured Async OSINT Scanning

> Explore Holehe's structured concurrency model using Trio for efficient OSINT scanning. Learn how Trio's primitives enable parallel lookups and deterministic task management.

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

---

**Holehe leverages Trio's structured concurrency primitives in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) to run parallel username lookups across hundreds of services, using a custom `TrioProgress` instrument to update progress bars while maintaining deterministic task lifecycles through nursery-based execution.**

The megadose/holehe repository implements a high-performance OSINT tool that checks username availability across platforms like Instagram, Spotify, and hundreds of others. At the heart of its performance lies a carefully designed async architecture that demonstrates exactly how Holehe's concurrency model works with Trio to handle simultaneous HTTP requests without resource leaks or orphaned coroutines.

## Trio Event Loop Initialization in core.py

The entry point for Holehe's async execution resides in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), where the synchronous CLI wrapper invokes `trio.run(maincore)` at line 233. This call bootstraps the Trio event loop, executes the `maincore()` async function, and blocks until the nursery scope completes or an unhandled exception propagates.

The module imports Trio at the top of the file (`import trio` at line 4), ensuring all subsequent async operations use Trio's structured concurrency guarantees rather than Python's standard asyncio.

## Structured Concurrency with Trio's Nursery Pattern

Inside `maincore()`, Holehe establishes a structured concurrency scope using `async with trio.open_nursery() as nursery:` at line 218. This nursery acts as a task group that guarantees all spawned children complete before the Python interpreter exits the `async with` block.

Each enabled platform module executes concurrently via `nursery.start_soon(module.check, ...)`, passing the nursery reference itself to child tasks. This design allows modules to spawn additional sub-tasks if needed, while Trio's cancellation semantics ensure that if one service check raises an exception, the entire nursery cancels immediately. This prevents orphaned coroutines and ensures that partial OSINT results do not persist when one check fails.

## Real-Time Progress Tracking via Custom Instruments

Before launching service checks, Holehe registers a custom instrumentation class defined in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py). At line 217, `trio.lowlevel.add_instrument(instrument)` installs the `TrioProgress` instance, which inherits from `trio.abc.Instrument`.

This instrument hooks into Trio's internal task scheduler to drive the tqdm progress bar. The class overrides methods like `task_spawned` and `before_task_step`, allowing the UI to update in real-time as Trio schedules task steps, all without blocking the concurrent HTTP requests running in the nursery.

After the nursery block completes—whether successfully or via cancellation—line 221 executes `trio.lowlevel.remove_instrument(instrument)` to detach the callback and free resources.

## Graceful Shutdown and Resource Cleanup

When the nursery context exits, the cleanup code in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) runs immediately. The explicit removal of the progress instrument prevents memory leaks, while Trio's structured concurrency guarantees that no tasks persist in the background after `maincore()` returns to the `trio.run()` caller.

The nursery's automatic cancellation propagation means that pressing Ctrl+C or encountering a network error in one module immediately signals all other running checks to abort, simplifying error handling compared to thread-based concurrency models.

## Implementation Example

The following pattern from [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) demonstrates the complete concurrency workflow:

```python
import trio
from holehe.instruments import TrioProgress
from holehe.modules import instagram, spotify

async def maincore(username):
    # Initialize progress tracking (line 217 in core.py)

    instrument = TrioProgress()
    trio.lowlevel.add_instrument(instrument)
    
    try:
        # Open structured concurrency scope (line 218 in core.py)

        async with trio.open_nursery() as nursery:
            # Launch concurrent checks for each module

            nursery.start_soon(instagram.check, username, nursery)
            nursery.start_soon(spotify.check, username, nursery)
            # Hundreds of additional modules...

    finally:
        # Ensure cleanup happens even on cancellation (line 221 in core.py)

        trio.lowlevel.remove_instrument(instrument)

# Entry point (line 233 in core.py)

if __name__ == "__main__":
    trio.run(maincore)

```

The `TrioProgress` class in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) implements the Instrument interface as follows:

```python
import trio
from tqdm import tqdm

class TrioProgress(trio.abc.Instrument):
    def __init__(self, total_tasks):
        self.bar = tqdm(total=total_tasks)
    
    def task_spawned(self, task):
        self.bar.update(0)  # Hook on task creation

    
    def before_task_step(self, task):
        self.bar.update(1)  # Increment on each scheduled step

```

## Summary

- **`trio.run(maincore)`** at line 233 of [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) initializes the Trio event loop and blocks until all username checks complete or fail.
- **`trio.open_nursery()`** at line 218 creates a structured concurrency scope where each service check runs as an independent async task with automatic cancellation propagation.
- **`nursery.start_soon()`** launches platform modules in parallel, passing the nursery reference to enable hierarchical task spawning.
- **`TrioProgress`** in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) implements `trio.abc.Instrument` to update the tqdm progress bar via `trio.lowlevel.add_instrument()` at line 217.
- **Explicit cleanup** at line 221 removes the instrument after the nursery closes, preventing memory leaks and ensuring deterministic resource management.

## Frequently Asked Questions

### Why does Holehe use Trio instead of asyncio for its concurrency model?

Trio enforces structured concurrency through nurseries, which eliminates common async bugs like orphaned tasks and unhandled exceptions in background jobs. In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the `async with trio.open_nursery()` block at line 218 guarantees that all spawned username checks complete or fail as a single unit, unlike asyncio's loosely coupled Task objects that can outlive their creators. This makes Holehe's OSINT scanning deterministic and significantly easier to debug when handling hundreds of simultaneous HTTP requests.

### How does the progress bar update without blocking async operations?

Holehe implements the `TrioProgress` class in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py), which inherits from `trio.abc.Instrument`. By registering it via `trio.lowlevel.add_instrument()` at line 217 of [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the code hooks into Trio's internal task scheduling events. The instrument updates a tqdm progress bar during `task_spawned` and `before_task_step` callbacks, allowing real-time UI feedback without interrupting the concurrent HTTP requests running in the nursery.

### What happens if one username check crashes while others are running?

Due to Trio's strict structured concurrency rules, an unhandled exception in any single check triggers immediate cancellation of the entire nursery. When `nursery.start_soon()` launches tasks at line 218, Trio monitors all children; if one raises an error, it cancels the others and propagates the exception to the `maincore()` function. This fail-fast behavior prevents partial OSINT results and ensures immediate resource cleanup through the `remove_instrument` call at line 221.

### How can I add a new service module to Holehe's Trio-based scanner?

New modules must implement an async `check` function that accepts the `nursery` parameter and respects Trio's cancellation semantics. Register the module in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) by adding `nursery.start_soon(your_module.check, username, nursery)` inside the `async with trio.open_nursery()` block at line 218. Use `httpx.AsyncClient` with timeout handling or `trio` APIs for I/O operations to ensure compatibility with Holehe's structured concurrency model.