Skip to main content

Create random delays for rate limiting, jitter, or testing

Project description

Random Delay

🎲 Create random delays for rate limiting, jitter, or testing.

Python 3.7+ PyPI version License: MIT Code style: black

Features

🚀 Multiple Delay Strategies

  • Uniform random delays
  • Exponential distribution delays
  • Normal (Gaussian) distribution delays
  • Exponential backoff with jitter
  • Custom delay functions

Async/Await Support

  • Full support for both sync and async operations
  • Non-blocking delays with asyncio

🎯 Easy Integration

  • Decorators for functions
  • Context managers
  • Direct delay calls

🔄 Retry Mechanisms

  • Automatic retries with configurable delays
  • Exception handling
  • Callback support

📊 Analysis Tools

  • Benchmark delay strategies
  • Distribution analysis
  • Performance metrics

Installation

pip install random-delay

For CLI support:

pip install random-delay[cli]

For development:

pip install random-delay[dev]

Quick Start

Basic Usage

import random_delay

# Create a uniform delay between 0.1 and 0.5 seconds
delay = random_delay.UniformDelay(min_delay=0.1, max_delay=0.5)

# Synchronous delay
delay.delay()

# Asynchronous delay
await delay.async_delay()

Using Decorators

from random_delay import delay, async_delay

# Add delay before function execution
@delay(min_delay=0.1, max_delay=0.5)
def api_call():
    return "API response"

# Async version
@async_delay(min_delay=0.1, max_delay=0.5)
async def async_api_call():
    return "Async API response"

Retry with Exponential Backoff

from random_delay import retry_with_delay, ExponentialBackoffDelay
import requests

@retry_with_delay(
    max_retries=3,
    delay_strategy=ExponentialBackoffDelay(base_delay=1.0, max_delay=60.0)
)
def fetch_data(url):
    response = requests.get(url)
    response.raise_for_status()
    return response.json()

Context Managers

from random_delay import DelayContext, UniformDelay

delay_strategy = UniformDelay(0.1, 0.5)

# Add delay when entering context
with DelayContext(delay_strategy, before=True):
    print("This executes after a random delay")

# Async version
async with AsyncDelayContext(delay_strategy, before=True, after=True):
    print("Delays before and after this block")

Delay Strategies

Uniform Delay

Random delay uniformly distributed between min and max values.

from random_delay import UniformDelay

delay = UniformDelay(min_delay=0.1, max_delay=1.0)

Exponential Delay

Delay following exponential distribution (good for simulating real-world wait times).

from random_delay import ExponentialDelay

delay = ExponentialDelay(lambd=1.0, max_delay=5.0)

Normal Delay

Delay following normal (Gaussian) distribution.

from random_delay import NormalDelay

delay = NormalDelay(mu=0.5, sigma=0.1, min_delay=0.1, max_delay=1.0)

Exponential Backoff

Delay that increases exponentially with each attempt (perfect for retries).

from random_delay import ExponentialBackoffDelay

delay = ExponentialBackoffDelay(
    base_delay=1.0,
    max_delay=60.0,
    multiplier=2.0,
    jitter=True
)

# Use for retries
for attempt in range(3):
    try:
        risky_operation()
        break
    except Exception:
        delay.delay()  # Wait longer each time

Custom Delay

Use your own function to generate delays.

from random_delay import CustomDelay
import random

def my_delay_func():
    return random.triangular(0.1, 1.0, 0.3)

delay = CustomDelay(my_delay_func)

Common Use Cases

Rate Limiting

from random_delay.utils import create_rate_limiter

# Limit to 10 requests per second with jitter
rate_limiter = create_rate_limiter(requests_per_second=10, jitter=True)

for i in range(100):
    rate_limiter.delay()
    make_api_request()

Preventing Thundering Herd

from random_delay import UniformDelay

# Add jitter to prevent all clients hitting at the same time
jitter = UniformDelay(0.0, 2.0)

def scheduled_task():
    jitter.delay()  # Random delay before execution
    perform_task()

Testing Network Conditions

from random_delay.utils import simulate_network_latency
from random_delay import CustomDelay

# Simulate network with 10-100ms latency and 1% packet loss
latency_sim = simulate_network_latency(
    min_latency=0.01,
    max_latency=0.1,
    packet_loss_rate=0.01
)

network_delay = CustomDelay(latency_sim)

def test_with_network_simulation():
    network_delay.delay()
    # Your network-dependent code here

Graceful Degradation

from random_delay import ExponentialBackoffDelay, async_retry_with_delay

backoff = ExponentialBackoffDelay(base_delay=0.1, max_delay=30.0)

@async_retry_with_delay(
    max_retries=5,
    delay_strategy=backoff,
    exceptions=(ConnectionError, TimeoutError)
)
async def robust_api_call():
    # This will retry with exponential backoff on connection errors
    async with aiohttp.ClientSession() as session:
        async with session.get('https://api.example.com/data') as response:
            return await response.json()

Command Line Interface

The package includes a CLI for testing and analysis:

# Run 10 uniform delays between 0.1 and 0.5 seconds
random-delay run --strategy uniform --min-delay 0.1 --max-delay 0.5 --count 10

# Benchmark exponential delays
random-delay benchmark --strategy exponential --iterations 1000

# Analyze delay distribution
random-delay analyze --strategy normal --samples 10000 --output analysis.json

Advanced Features

Interrupting Delays

import threading
from random_delay import UniformDelay

delay = UniformDelay(5.0, 10.0)

# In another thread
def interrupt_after_timeout():
    time.sleep(2.0)
    delay.interrupt()

threading.Thread(target=interrupt_after_timeout).start()

try:
    delay.delay()  # Will be interrupted after 2 seconds
except DelayInterruptedError:
    print("Delay was interrupted")

Benchmarking Strategies

from random_delay.utils import benchmark_delay_strategy
from random_delay import UniformDelay

delay = UniformDelay(0.01, 0.1)
results = benchmark_delay_strategy(delay, iterations=1000, async_mode=True)

print(f"Average delay: {results['delays']['mean']:.4f}s")
print(f"Overhead: {results['overhead']['mean']*1000:.2f}ms")

Distribution Analysis

from random_delay.utils import delay_distribution_analysis
from random_delay import NormalDelay

delay = NormalDelay(mu=0.5, sigma=0.1)
analysis = delay_distribution_analysis(delay, samples=10000)

print(f"Mean: {analysis['mean']:.4f}s")
print(f"Std Dev: {analysis['stdev']:.4f}s")
print(f"95th percentile: {analysis['percentiles']['p95']:.4f}s")

Performance Considerations

  • Async delays are more efficient for I/O-bound applications
  • Thread overhead is minimal for short delays (< 1ms)
  • Memory usage is constant regardless of delay duration
  • Jitter adds ~10-20μs overhead but prevents thundering herd

Best Practices

For Rate Limiting

# ✅ Good: Use jitter to prevent thundering herd
rate_limiter = create_rate_limiter(10, jitter=True)

# ❌ Avoid: Fixed delays can cause synchronized requests
fixed_delay = CustomDelay(lambda: 0.1)

For Retries

# ✅ Good: Exponential backoff with jitter
backoff = ExponentialBackoffDelay(base_delay=1.0, jitter=True)

# ❌ Avoid: Linear backoff can be too aggressive
linear_delay = CustomDelay(lambda: attempt * 1.0)

For Testing

# ✅ Good: Use realistic distributions
realistic_delay = NormalDelay(mu=0.1, sigma=0.02)

# ❌ Avoid: Unrealistic uniform delays
unrealistic_delay = UniformDelay(0.001, 10.0)

API Reference

Core Classes

  • RandomDelay - Abstract base class for all delay strategies
  • UniformDelay - Uniform random delays
  • ExponentialDelay - Exponential distribution delays
  • NormalDelay - Normal distribution delays
  • ExponentialBackoffDelay - Exponential backoff with jitter
  • CustomDelay - User-defined delay functions

Decorators

  • @delay - Add delays to synchronous functions
  • @async_delay - Add delays to asynchronous functions
  • @retry_with_delay - Retry with delay on exception
  • @async_retry_with_delay - Async retry with delay

Context Managers

  • DelayContext - Synchronous delay context manager
  • AsyncDelayContext - Asynchronous delay context manager

Utilities

  • create_rate_limiter - Create rate limiting delays
  • create_exponential_backoff - Create exponential backoff
  • simulate_network_latency - Simulate network conditions
  • benchmark_delay_strategy - Benchmark performance
  • delay_distribution_analysis - Analyze distributions

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

git clone https://github.com/yourusername/random-delay.git
cd random-delay
pip install -e ".[dev]"

Running Tests

pytest
pytest --cov=random_delay  # With coverage

Code Formatting

black random_delay/
isort random_delay/
flake8 random_delay/

Why Random Delays?

Random delays are essential for building robust distributed systems:

  • Prevents thundering herd - Avoids all clients hitting resources simultaneously
  • Improves system stability - Spreads load over time
  • Better user experience - Graceful degradation under load
  • Testing realism - Simulates real-world network conditions
  • Rate limiting - Respects API limits and prevents abuse

Perfect for microservices, API clients, testing frameworks, and any system that needs intelligent delay strategies!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

random_delay-1.0.0.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

random_delay-1.0.0-py3-none-any.whl (14.6 kB view details)

Uploaded Python 3

File details

Details for the file random_delay-1.0.0.tar.gz.

File metadata

  • Download URL: random_delay-1.0.0.tar.gz
  • Upload date:
  • Size: 15.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.0

File hashes

Hashes for random_delay-1.0.0.tar.gz
Algorithm Hash digest
SHA256 6022c7844aff68fa3dd3d89bac0b64113e27c48402d8766de2c6ea6b05147e6c
MD5 807d926bb974ca6ea27356b2b1d9a8e6
BLAKE2b-256 e1d9f0d5d4d84c87b991a7f7d74e3477903d1b10d6b9890d33fbdc8da44a95f4

See more details on using hashes here.

File details

Details for the file random_delay-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: random_delay-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 14.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.0

File hashes

Hashes for random_delay-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7d7203ffd83f625b49ce0485aa112aca69f37c91141e8fdb888081d7505a86a1
MD5 85812dbd8a7aa8945cc1cace50dd1258
BLAKE2b-256 752ac043f84ab5bc68ca00392520d7809c95a501f9e534db672455a8bffe65c9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page