How to Configure Rate Limiting and Memory-Adaptive Dispatchers in Crawl4AI
Configure rate limiting and memory-adaptive dispatchers in Crawl4AI by instantiating a RateLimiter to manage per-domain request delays and passing it to a MemoryAdaptiveDispatcher that monitors system RAM via psutil to prevent out-of-memory crashes during large-scale crawls.
The crawl4ai library decouples crawling logic from concurrency management through pluggable dispatcher components. By separating the "what" (crawler logic) from the "how" (job dispatching), you can fine-tune request throttling and safeguard system resources when processing hundreds of concurrent URLs.
Understanding the Dispatcher Architecture
Crawl4AI provides two primary dispatcher classes in crawl4ai/async_dispatcher.py that work together to control execution flow:
RateLimiter: Manages per-domain request pacing, exponential back-off on HTTP 429/503 responses, and retry limits (lines 28-85).MemoryAdaptiveDispatcher: Monitors real-time memory consumption, toggles "pressure mode" when thresholds are crossed, and re-queues tasks to prevent OOM errors (lines 48-66 for initialization, lines 75-104 for the monitor task).
The RateLimiter maintains domain-specific state using the DomainState class defined in crawl4ai/models.py, while the MemoryAdaptiveDispatcher relies on get_true_memory_usage_percent from crawl4ai/utils.py to poll system resources.
Configuring the RateLimiter
The RateLimiter class inserts randomized delays between requests to the same domain and automatically adjusts timing when rate-limit responses are detected.
Constructor Parameters
Instantiate the limiter with precise control over back-off behavior:
from crawl4ai.async_dispatcher import RateLimiter
rl = RateLimiter(
base_delay=(0.5, 2.0), # Random delay between 0.5s and 2.0s
max_delay=30.0, # Cap delay at 30 seconds
max_retries=5, # Retry up to 5 times
rate_limit_codes=[429, 503] # Consider these status codes as rate limits
)
The wait_if_needed method checks the domain's last request timestamp before allowing new connections, while update_delay implements exponential back-off when the server returns rate-limit codes (lines 69-78 in async_dispatcher.py).
Implementing Memory-Adaptive Dispatching
The MemoryAdaptiveDispatcher wraps your rate limiter and adds memory-aware task scheduling to protect host resources.
Memory Threshold Parameters
Configure the dispatcher with three distinct RAM thresholds:
from crawl4ai.async_dispatcher import MemoryAdaptiveDispatcher
dispatcher = MemoryAdaptiveDispatcher(
memory_threshold_percent=85.0, # Enter pressure mode
critical_threshold_percent=95.0, # Aggressive re-queuing
recovery_threshold_percent=75.0, # Exit pressure mode
max_session_permit=20, # Max concurrent sessions
fairness_timeout=600.0, # Prevent task starvation
memory_wait_timeout=600.0, # Hard timeout for pressure
rate_limiter=rl # Your RateLimiter instance
)
When system RAM exceeds memory_threshold_percent, the dispatcher enters pressure mode and assigns higher priority to new tasks. Crossing critical_threshold_percent triggers immediate re-queuing of active tasks with incremented retry counts and negative priority values (lines 90-106).
The Memory Monitor Task
The dispatcher spawns a background coroutine _memory_monitor_task that polls psutil every second (configurable via check_interval). This task toggles the memory_pressure_mode flag based on current usage relative to your configured thresholds.
Complete Integration Example
Combine both dispatchers with AsyncWebCrawler to process URL batches safely:
from crawl4ai import AsyncWebCrawler
from crawl4ai.config import CrawlerRunConfig
from crawl4ai.async_dispatcher import RateLimiter, MemoryAdaptiveDispatcher
# 1. Configure rate limiting
rate_limiter = RateLimiter(
base_delay=(1.0, 2.0),
max_delay=30.0,
max_retries=3,
rate_limit_codes=[429]
)
# 2. Configure memory-adaptive dispatching
dispatcher = MemoryAdaptiveDispatcher(
memory_threshold_percent=80.0,
critical_threshold_percent=92.0,
max_session_permit=15,
fairness_timeout=300.0,
rate_limiter=rate_limiter
)
# 3. Initialize crawler
crawler = AsyncWebCrawler()
config = CrawlerRunConfig()
# 4. Process URLs with automatic throttling and memory protection
urls = ["https://example.com/page1", "https://example.com/page2"]
results = await dispatcher.run_urls(urls, crawler, config)
For streaming results, use run_urls_stream instead:
async for result in dispatcher.run_urls_stream(urls, crawler, config):
print(f"{result.url}: success={result.result.success}")
Customizing Dispatcher Behavior
Tailor the dispatchers to your specific workload requirements:
- Per-domain strategies: Modify
rate_limit_codesto include 403 responses or adjustmax_retriesfor stubborn endpoints. - Aggressive memory handling: Lower
memory_threshold_percentto 70.0 for early conservation, or setmemory_wait_timeout=Noneto allow indefinite waiting during pressure. - Fairness tuning: Increase
fairness_timeoutfor strict FIFO ordering, or decrease it to prioritize long-waiting URLs and prevent starvation.
You can also nest dispatchers by passing a SemaphoreDispatcher as the base dispatcher argument in higher-level configurations (see docs/examples/dispatcher_example.py).
Summary
- RateLimiter in
crawl4ai/async_dispatcher.pyprovides per-domain throttling with exponential back-off for HTTP 429/503 responses. - MemoryAdaptiveDispatcher monitors RAM via
psutil, toggles pressure mode at configurable thresholds, and re-queues tasks to prevent OOM crashes. - Both dispatchers integrate seamlessly with
AsyncWebCrawlerthrough therun_urlsandrun_urls_streammethods. - Configure
memory_threshold_percent,critical_threshold_percent, andrecovery_threshold_percentto define custom memory safety zones. - The
_memory_monitor_taskcoroutine polls system resources every second, ensuring real-time adaptation to memory pressure.
Frequently Asked Questions
What is the difference between RateLimiter and MemoryAdaptiveDispatcher?
RateLimiter manages request pacing and server-friendly back-off behaviors, tracking per-domain state to prevent overwhelming target servers. MemoryAdaptiveDispatcher manages local system resources, monitoring RAM usage to prevent your crawling process from consuming all available memory and crashing.
How does the memory monitor detect pressure?
The dispatcher spawns a background _memory_monitor_task that calls get_true_memory_usage_percent from crawl4ai/utils.py (which wraps psutil) every check_interval seconds. When reported RAM exceeds memory_threshold_percent, the dispatcher sets memory_pressure_mode to true, triggering priority adjustments and potential task re-queuing.
Can I use RateLimiter without MemoryAdaptiveDispatcher?
Yes, the RateLimiter is a standalone class that can be used with other dispatcher types or custom async implementations. However, MemoryAdaptiveDispatcher requires a rate_limiter parameter to handle per-domain throttling while managing memory constraints, making the combination recommended for production workloads.
What happens when the critical memory threshold is reached?
When RAM usage exceeds critical_threshold_percent, the dispatcher immediately re-queues the current task with a negative priority value (higher priority) and increments its retry count, logging "Requeued due to critical memory pressure". This prevents the crawler from holding memory-intensive resources while the system is under extreme pressure.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →