1.0.0 โ€ข Published 5 months ago

@bcoders.gr/virtualpool v1.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

@bcoders.gr/virtualpool

Advanced Ethereum testing framework with provider pooling, load balancing, and comprehensive monitoring.

Features

  • ๐Ÿš€ Provider Pooling: Manage multiple Anvil instances efficiently
  • โš–๏ธ Load Balancing: Multiple strategies (random, round-robin, least-used, fastest)
  • ๐Ÿ“Š Monitoring: Comprehensive metrics and health checks
  • ๐Ÿ”„ Auto-recovery: Automatic provider restart on failure
  • ๐ŸŽฏ Circuit Breaker: Prevent cascading failures
  • ๐Ÿงช Testing Ready: Built for extensive blockchain testing

Installation

npm install @bcoders.gr/virtualpool

Quick Start

import AnvilProviderPool from '@bcoders.gr/virtualpool';

// Create a pool with 3 providers on ports 8545-8547
const pool = new AnvilProviderPool(8545, 8547, {
    timeout: 30000,
    maxRetries: 5,
    healthCheckInterval: 30000
});

// Initialize the pool
await pool.initialize();

// Use a provider with automatic management
const blockNumber = await pool.withProvider(async (provider) => {
    return await provider.send('eth_blockNumber', []);
});

console.log(`Current block: ${parseInt(blockNumber, 16)}`);

// Shutdown when done
await pool.shutdown();

API Reference

Constructor

new AnvilProviderPool(portStart, portEnd, options)

Parameters:

  • portStart (number): Starting port for Anvil instances
  • portEnd (number): Ending port for Anvil instances
  • options (object): Configuration options

Options:

  • timeout (number): Provider startup timeout (default: 30000ms)
  • maxRetries (number): Max retry attempts (default: 5)
  • maxRetriesPerPort (number): Max retries per port (default: 3)
  • healthCheckInterval (number): Health check interval (default: 30000ms)
  • anvilPath (string): Path to anvil binary (default: '/root/.foundry/bin/anvil')
  • maxParallelStarts (number): Max parallel provider starts (default: 5)
  • waitInterval (number): Wait interval for provider availability (default: 10ms)
  • gracefulShutdownTimeout (number): Graceful shutdown timeout (default: 5000ms)
  • logger (function): Custom logger function
  • providerOptions (object): Options passed to IPCProvider

Methods

initialize()

Initialize all providers in the pool.

await pool.initialize();

withProvider(fn)

Execute a function with an automatically managed provider.

const result = await pool.withProvider(async (provider) => {
    return await provider.send('eth_getBalance', [address, 'latest']);
});

withProviderWait(fn, timeoutMs)

Execute a function with a provider, waiting if none available.

const result = await pool.withProviderWait(async (provider) => {
    return await provider.send('eth_call', [transaction, 'latest']);
}, 10000);

withProviderStrategy(fn, strategy, timeoutMs)

Execute a function using a specific load balancing strategy.

const result = await pool.withProviderStrategy(async (provider) => {
    return await provider.send('eth_chainId', []);
}, 'roundRobin');

Strategies:

  • 'random': Random provider selection (default)
  • 'roundRobin': Round-robin selection
  • 'leastUsed': Select least used provider
  • 'fastest': Select fastest responding provider

getAvailableProvider()

Get an available provider manually (for advanced use cases).

const providerInfo = pool.getAvailableProvider();
if (providerInfo) {
    const { provider, port } = providerInfo;
    // Use provider...
    pool.releaseProvider(port); // Don't forget to release!
}

getStats()

Get comprehensive pool statistics.

const stats = pool.getStats();
console.log(`Available: ${stats.available}/${stats.total}`);
console.log(`Success rate: ${stats.successRate}`);
console.log(`Avg response time: ${stats.averageResponseTime}ms`);

shutdown(forceTimeout)

Gracefully shutdown the pool.

await pool.shutdown(10000); // 10 second force timeout

Events

The pool emits various events for monitoring:

pool.on('requestCompleted', ({ port, responseTime, success }) => {
    console.log(`Request on port ${port}: ${responseTime}ms, success: ${success}`);
});

pool.on('providerFailed', ({ port, error }) => {
    console.log(`Provider ${port} failed: ${error}`);
});

pool.on('providerRecovered', ({ port }) => {
    console.log(`Provider ${port} recovered`);
});

pool.on('healthCheckCompleted', (stats) => {
    console.log(`Health check completed, ${stats.healthy} healthy providers`);
});

Advanced Usage

Custom Configuration

const pool = new AnvilProviderPool(8545, 8549, {
    timeout: 60000,
    maxRetries: 10,
    healthCheckInterval: 60000,
    logger: (msg) => console.log(`[POOL] ${msg}`),
    providerOptions: {
        requestTimeout: 30000,
        autoReconnect: true
    }
});

Error Handling

try {
    await pool.initialize();
} catch (error) {
    console.error('Failed to initialize pool:', error.message);
    // Handle initialization failure
}

try {
    const result = await pool.withProvider(async (provider) => {
        return await provider.send('eth_getTransactionReceipt', [txHash]);
    });
} catch (error) {
    console.error('Transaction failed:', error.message);
    // Handle request failure
}

Monitoring

// Regular stats monitoring
setInterval(() => {
    const stats = pool.getStats();
    console.log(`Pool utilization: ${stats.utilizationRate}`);
    console.log(`Requests/sec: ${stats.requestsPerSecond}`);
}, 10000);

// Event-based monitoring
pool.on('requestCompleted', ({ port, responseTime, success, totalRequests }) => {
    if (!success) {
        console.warn(`Failed request on port ${port}`);
    }
    if (totalRequests % 1000 === 0) {
        console.log(`Processed ${totalRequests} requests`);
    }
});

Testing

The package includes comprehensive tests:

npm run test:basic           # Basic functionality
npm run test:comprehensive   # Full test suite
npm run test:getavailable    # Provider allocation tests

Requirements

  • Node.js >= 16.0.0
  • Foundry with Anvil installed
  • Linux/macOS (Windows support via WSL)

License

MIT License - see LICENSE file for details.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

Support


Built with โค๏ธ by bcoders.gr