# @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

```bash
npm install @bcoders.gr/virtualpool
```

## Quick Start

```javascript
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

```javascript
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.

```javascript
await pool.initialize();
```

#### `withProvider(fn)`
Execute a function with an automatically managed provider.

```javascript
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.

```javascript
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.

```javascript
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).

```javascript
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.

```javascript
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.

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

## Events

The pool emits various events for monitoring:

```javascript
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

```javascript
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

```javascript
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

```javascript
// 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:

```bash
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](https://getfoundry.sh/) with Anvil installed
- Linux/macOS (Windows support via WSL)

## License

MIT License - see [LICENSE](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

- GitHub Issues: [Report bugs or request features](https://github.com/pagovitsa/virtualpool/issues)
- Documentation: [Full API documentation](https://github.com/pagovitsa/virtualpool/wiki)

---

Built with ❤️ by [bcoders.gr](https://bcoders.gr)
