Skip to content

Commit 19061dc

Browse files
Fix AsyncFuzzExecutor docs to match implementation and fix blocking s… (#116)
* Fix AsyncFuzzExecutor docs to match implementation and fix blocking stdio reads
1 parent b7310bb commit 19061dc

File tree

13 files changed

+813
-726
lines changed

13 files changed

+813
-726
lines changed

docs/architecture/architecture.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -665,22 +665,20 @@ The `AsyncFuzzExecutor` provides controlled concurrency and robust error handlin
665665

666666
**Error Handling:**
667667

668-
- **Timeout Management**: Configurable timeouts for individual operations
669-
- **Retry Logic**: Exponential backoff retry mechanism for failed operations
670-
- **Exception Collection**: Collects and categorizes errors from batch operations
668+
- **Automatic Error Collection**: Automatically collects and categorizes errors from batch operations
669+
- **Thread Pool Support**: Handles both async and sync operations via thread pool
670+
- **Hypothesis Integration**: Wraps Hypothesis strategies to prevent asyncio deadlocks
671+
- **Graceful Failure**: Operations can fail without stopping the entire batch
671672

672673
**Configuration Options:**
673674

674675
- `max_concurrency`: Maximum number of concurrent operations (default: 5)
675-
- `timeout`: Default timeout for operations (default: 30.0 seconds)
676-
- `retry_count`: Number of retries for failed operations (default: 1)
677-
- `retry_delay`: Delay between retries (default: 1.0 seconds)
678676

679677
**Usage Patterns:**
680678

681-
- **Single Operations**: Execute individual operations with timeout and error handling
682-
- **Retry Operations**: Execute operations with automatic retry on failure
683-
- **Batch Operations**: Execute multiple operations concurrently with bounded concurrency
679+
- **Batch Operations**: Execute multiple operations concurrently with bounded concurrency and automatic error collection
680+
- **Mixed Operations**: Handle both async and sync operations in the same batch
681+
- **Hypothesis Strategies**: Run Hypothesis strategies safely in thread pool
684682

685683
## Execution Flow
686684

Lines changed: 75 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Async Executor
22

3-
The AsyncFuzzExecutor is a core component that bridges the strategy components (test case generators) and the fuzzing engine. It provides a robust asynchronous execution framework with concurrency control, error handling, and retry mechanisms.
3+
The AsyncFuzzExecutor is a core component that bridges the strategy components (test case generators) and the fuzzing engine. It provides a robust asynchronous execution framework with semaphore-based concurrency control and error handling.
44

55
## Architecture
66

@@ -12,75 +12,101 @@ graph TD
1212
B -->|Execute with Concurrency Control| C[Fuzzing Engine]
1313
C -->|Results| D[Result Collection]
1414
B -->|Error Handling| E[Error Processing]
15-
B -->|Retry Logic| F[Retry Mechanism]
15+
B -->|Thread Pool| F[Sync Operations]
1616
```
1717

1818
## Features
1919

20-
- **Concurrency Control**: Limits the number of concurrent operations to prevent resource exhaustion
21-
- **Timeout Handling**: Enforces timeouts on operations to prevent hanging
22-
- **Error Handling**: Captures and processes exceptions from operations
23-
- **Retry Mechanism**: Automatically retries failed operations with exponential backoff
20+
- **Concurrency Control**: Uses semaphore to limit the number of concurrent operations
21+
- **Error Handling**: Captures and collects exceptions from operations automatically
2422
- **Batch Execution**: Executes multiple operations concurrently with result aggregation
25-
- **Resource Management**: Proper cleanup of resources during shutdown
23+
- **Mixed Execution**: Handles both async and sync operations via thread pool
24+
- **Hypothesis Integration**: Wraps Hypothesis strategies to prevent asyncio deadlocks
25+
- **Resource Management**: Proper cleanup of thread pool resources during shutdown
2626

2727
## Usage
2828

29-
### Basic Execution
29+
### Batch Execution
3030

3131
```python
3232
from mcp_fuzzer.fuzz_engine.executor import AsyncFuzzExecutor
3333

3434
# Create an executor with max concurrency of 5
3535
executor = AsyncFuzzExecutor(max_concurrency=5)
3636

37-
# Execute an async operation
38-
async def my_operation(value):
39-
# Some async operation
40-
return value * 2
41-
42-
result = await executor.execute(my_operation, 10)
37+
try:
38+
# Define an async operation
39+
async def my_operation(value):
40+
# Some async operation
41+
return value * 2
42+
43+
# Prepare operations as (function, args, kwargs) tuples
44+
operations = [
45+
(my_operation, [5], {}),
46+
(my_operation, [10], {}),
47+
(my_operation, [15], {})
48+
]
49+
50+
# Execute all operations concurrently
51+
results = await executor.execute_batch(operations)
52+
53+
# Process successful results
54+
for result in results["results"]:
55+
print(f"Success: {result}")
56+
57+
# Process errors
58+
for error in results["errors"]:
59+
print(f"Error: {error}")
60+
61+
finally:
62+
# Shutdown the executor and clean up resources
63+
await executor.shutdown()
4364
```
4465

45-
### Retry Mechanism
66+
### Error Handling
4667

4768
```python
48-
# Execute with retry
49-
result = await executor.execute_with_retry(
50-
my_operation,
51-
10,
52-
retry_count=3,
53-
retry_delay=1.0
54-
)
69+
async def operation_with_errors(value):
70+
if value % 2 == 0:
71+
raise ValueError(f"Even value not allowed: {value}")
72+
return value * 2
73+
74+
# Errors are automatically collected
75+
operations = [(operation_with_errors, [i], {}) for i in range(10)]
76+
results = await executor.execute_batch(operations)
77+
78+
print(f"Successful: {len(results['results'])}")
79+
print(f"Failed: {len(results['errors'])}")
5580
```
5681

57-
### Batch Execution
82+
### Mixed Async and Sync Operations
5883

5984
```python
60-
# Define multiple operations
85+
# Async operation
86+
async def async_op():
87+
await asyncio.sleep(0.1)
88+
return "async"
89+
90+
# Sync operation (runs in thread pool)
91+
def sync_op():
92+
return sum(range(1000))
93+
6194
operations = [
62-
(my_operation, [5], {}),
63-
(my_operation, [10], {}),
64-
(my_operation, [15], {})
95+
(async_op, [], {}),
96+
(sync_op, [], {})
6597
]
6698

67-
# Execute all operations concurrently
6899
results = await executor.execute_batch(operations)
69-
70-
# Process successful results
71-
for result in results["results"]:
72-
print(f"Success: {result}")
73-
74-
# Process errors
75-
for error in results["errors"]:
76-
print(f"Error: {error}")
77100
```
78101

79-
### Cleanup
102+
### Hypothesis Strategy Integration
80103

81104
```python
82-
# Shutdown the executor and clean up resources
83-
await executor.shutdown()
105+
from hypothesis import strategies as st
106+
107+
# Run Hypothesis strategy without asyncio deadlocks
108+
int_strategy = st.integers(min_value=0, max_value=100)
109+
value = await executor.run_hypothesis_strategy(int_strategy)
84110
```
85111

86112
## Integration with Fuzzing Components
@@ -96,6 +122,13 @@ This separation of concerns allows for better maintainability and scalability of
96122
## Configuration Options
97123

98124
- **max_concurrency**: Maximum number of concurrent operations (default: 5)
99-
- **timeout**: Default timeout for operations in seconds (default: 30.0)
100-
- **retry_count**: Number of retries for failed operations (default: 1)
101-
- **retry_delay**: Delay between retries in seconds (default: 1.0)
125+
126+
## API Methods
127+
128+
- `async execute_batch(operations) -> Dict[str, List]`: Execute a batch of operations
129+
- Operations format: `[(function, args, kwargs), ...]`
130+
- Returns: `{"results": [...], "errors": [...]}`
131+
132+
- `async run_hypothesis_strategy(strategy) -> Any`: Run Hypothesis strategy in thread pool
133+
134+
- `async shutdown() -> None`: Shutdown executor and clean up thread pool

docs/components/process-management-guide.md

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,7 @@ import os
248248

249249
# Use CPU count for CPU-bound operations
250250
cpu_executor = AsyncFuzzExecutor(
251-
max_concurrency=os.cpu_count(),
252-
timeout=60.0,
253-
retry_count=1
251+
max_concurrency=os.cpu_count()
254252
)
255253
```
256254

@@ -259,9 +257,7 @@ cpu_executor = AsyncFuzzExecutor(
259257
```python
260258
# Use higher concurrency for I/O-bound operations
261259
io_executor = AsyncFuzzExecutor(
262-
max_concurrency=os.cpu_count() * 2,
263-
timeout=30.0,
264-
retry_count=2
260+
max_concurrency=os.cpu_count() * 2
265261
)
266262
```
267263

@@ -270,37 +266,13 @@ io_executor = AsyncFuzzExecutor(
270266
```python
271267
# Conservative concurrency for network operations
272268
network_executor = AsyncFuzzExecutor(
273-
max_concurrency=10,
274-
timeout=15.0,
275-
retry_count=3,
276-
retry_delay=0.5
269+
max_concurrency=10
277270
)
278271
```
279272

280273
### Error Handling Patterns
281274

282-
#### Retry with Exponential Backoff
283-
284-
```python
285-
async def robust_operation():
286-
executor = AsyncFuzzExecutor(
287-
retry_count=3,
288-
retry_delay=1.0 # Base delay, will be doubled each retry
289-
)
290-
291-
async def unreliable_operation():
292-
# Operation that might fail
293-
pass
294-
295-
try:
296-
result = await executor.execute_with_retry(unreliable_operation)
297-
return result
298-
except Exception as e:
299-
logger.error(f"Operation failed after retries: {e}")
300-
raise
301-
```
302-
303-
#### Batch Processing with Error Collection
275+
#### Batch Processing with Automatic Error Collection
304276

305277
```python
306278
async def batch_processing_example():
@@ -473,9 +445,7 @@ debug_config = WatchdogConfig(
473445

474446
```python
475447
debug_executor = AsyncFuzzExecutor(
476-
max_concurrency=1, # Single operation for debugging
477-
timeout=5.0, # Shorter timeout
478-
retry_count=0 # No retries for debugging
448+
max_concurrency=1 # Single operation for debugging
479449
)
480450
```
481451

docs/components/process-management.md

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -56,37 +56,28 @@ import asyncio
5656
async def main():
5757
# Create executor with concurrency control
5858
executor = AsyncFuzzExecutor(
59-
max_concurrency=5, # Maximum concurrent operations
60-
timeout=30.0, # Default timeout in seconds
61-
retry_count=2, # Number of retries for failed operations
62-
retry_delay=1.0 # Delay between retries in seconds
59+
max_concurrency=5 # Maximum concurrent operations
6360
)
6461

65-
# Define an async operation
66-
async def my_operation(value):
67-
await asyncio.sleep(0.1) # Simulate work
68-
return value * 2
69-
70-
# Execute a single operation
71-
result = await executor.execute(my_operation, 5)
72-
print(f"Single operation result: {result}")
73-
74-
# Execute with retry mechanism
75-
result = await executor.execute_with_retry(my_operation, 10)
76-
print(f"Operation with retry: {result}")
62+
try:
63+
# Define an async operation
64+
async def my_operation(value):
65+
await asyncio.sleep(0.1) # Simulate work
66+
return value * 2
7767

78-
# Execute batch operations concurrently
79-
operations = [
80-
(my_operation, [5], {}),
81-
(my_operation, [10], {}),
82-
(my_operation, [15], {})
83-
]
68+
# Execute batch operations concurrently
69+
operations = [
70+
(my_operation, [5], {}),
71+
(my_operation, [10], {}),
72+
(my_operation, [15], {})
73+
]
8474

85-
batch_results = await executor.execute_batch(operations)
86-
print(f"Batch results: {batch_results['results']}")
75+
batch_results = await executor.execute_batch(operations)
76+
print(f"Batch results: {batch_results['results']}")
8777

88-
# Shutdown the executor
89-
await executor.shutdown()
78+
finally:
79+
# Shutdown the executor
80+
await executor.shutdown()
9081

9182
asyncio.run(main())
9283
```

0 commit comments

Comments
 (0)