CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-eclipse-jetty--jetty-client

Eclipse Jetty HTTP Client - A lightweight, asynchronous HTTP client library that supports HTTP/1.1, HTTP/2, WebSocket, and various authentication mechanisms, proxy configurations, and connection pooling strategies.

Pending
Overview
Eval results
Files

connection-pooling.mddocs/

Connection Pooling

The connection pooling capability provides multiple connection pool strategies for optimizing connection reuse and performance, including duplex, multiplex, round-robin, and random selection pools with comprehensive connection lifecycle management.

ConnectionPool Interface

The base interface for all connection pool implementations.

public interface ConnectionPool extends Closeable {
    // Connection acquisition and release
    CompletableFuture<Connection> acquire(boolean create);
    boolean release(Connection connection);
    boolean remove(Connection connection);
    
    // Pool management
    void close();
    boolean isClosed();
    
    // Pool statistics
    int getConnectionCount();
    int getIdleConnectionCount();
    int getActiveConnectionCount();
    
    // Pool configuration
    int getMaxConnectionCount();
    
    // Preconnection
    CompletableFuture<Void> preCreateConnections(int connectionCount);
}

DuplexConnectionPool

Connection pool for HTTP/1.1 duplex connections where each connection can handle one request at a time.

DuplexConnectionPool Class

public class DuplexConnectionPool extends AbstractConnectionPool {
    public DuplexConnectionPool(Destination destination, int maxConnections, Callback requester);
    public DuplexConnectionPool(Destination destination, int maxConnections, boolean cache, Callback requester);
    
    // Configuration
    public boolean isCache();
    public int getMaxDuplexCount();
}

Usage Examples

// Configure HttpClient with duplex connection pool
HttpClient client = new HttpClient();
client.start();

// Default connection pool settings
// - Max connections per destination: typically 64
// - Connection caching: enabled
// - Suitable for HTTP/1.1 connections

// Make concurrent requests - each uses separate connection
List<CompletableFuture<ContentResponse>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    CompletableFuture<ContentResponse> future = client.newRequest("https://api.example.com/data/" + i).send();
    futures.add(future);
}

// Wait for all requests to complete
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
    .thenRun(() -> {
        System.out.println("All requests completed");
        futures.forEach(future -> {
            try {
                ContentResponse response = future.get();
                System.out.println("Response: " + response.getStatus());
            } catch (Exception e) {
                System.err.println("Request failed: " + e.getMessage());
            }
        });
    });

MultiplexConnectionPool

Connection pool for HTTP/2 multiplex connections where each connection can handle multiple concurrent requests.

MultiplexConnectionPool Class

public class MultiplexConnectionPool extends AbstractConnectionPool {
    public MultiplexConnectionPool(Destination destination, int maxConnections, Callback requester, int maxMultiplex);
    
    // Configuration
    public int getMaxMultiplex();
}

Usage Examples

// Configure HttpClient for HTTP/2 with multiplex connection pool
HttpClient client = new HttpClient();

// Enable HTTP/2
client.setProtocols(List.of("h2", "http/1.1"));
client.start();

// HTTP/2 connections can multiplex many requests over single connection
// Default max multiplex: typically 1024 streams per connection

// Make many concurrent requests over fewer connections
List<CompletableFuture<ContentResponse>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    CompletableFuture<ContentResponse> future = client.newRequest("https://http2.example.com/api/data/" + i).send();
    futures.add(future);
}

// All requests may use the same HTTP/2 connection with multiplexing
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
    .thenRun(() -> System.out.println("All HTTP/2 requests completed"));

RoundRobinConnectionPool

Connection pool that distributes requests across available connections in round-robin fashion.

RoundRobinConnectionPool Class

public class RoundRobinConnectionPool extends AbstractConnectionPool {
    public RoundRobinConnectionPool(Destination destination, int maxConnections, Callback requester);
    public RoundRobinConnectionPool(Destination destination, int maxConnections, Callback requester, int maxMultiplex);
}

Usage Examples

// Round-robin is useful for load balancing across multiple connections
// Typically used with HTTP/1.1 where you want to distribute load evenly

public class RoundRobinClient {
    private final HttpClient client;
    
    public RoundRobinClient() throws Exception {
        this.client = new HttpClient();
        
        // Configure connection factory to use round-robin pool
        // Note: Direct pool configuration is typically done at transport level
        
        client.start();
    }
    
    public void makeBalancedRequests() throws Exception {
        // Make requests that will be distributed round-robin across connections
        for (int i = 0; i < 20; i++) {
            final int requestId = i;
            client.newRequest("https://api.example.com/endpoint/" + i)
                .send(result -> {
                    if (result.isSucceeded()) {
                        System.out.println("Request " + requestId + " completed on connection: " + 
                                         result.getRequest().getConnection());
                    }
                });
        }
    }
}

RandomConnectionPool

Connection pool that randomly selects from available connections.

RandomConnectionPool Class

public class RandomConnectionPool extends AbstractConnectionPool {
    public RandomConnectionPool(Destination destination, int maxConnections, Callback requester);
    public RandomConnectionPool(Destination destination, int maxConnections, Callback requester, int maxMultiplex);
}

Usage Examples

// Random selection can help avoid hot-spotting on specific connections
// Useful when you want to distribute load unpredictably

public class RandomizedLoadClient {
    public void demonstrateRandomPool() {
        // Random connection selection helps with:
        // - Avoiding connection hot-spots
        // - Better distribution in some network topologies
        // - Testing resilience across different connections
        
        // Requests will be randomly distributed across available connections
        for (int i = 0; i < 50; i++) {
            client.GET("https://distributed.example.com/api/data");
        }
    }
}

ValidatingConnectionPool

Connection pool that validates connections before use to ensure they are still functional.

ValidatingConnectionPool Class

public class ValidatingConnectionPool extends DuplexConnectionPool {
    public ValidatingConnectionPool(Destination destination, int maxConnections, Callback requester);
    
    // Validation configuration
    public void setValidationTimeout(long validationTimeout);
    public long getValidationTimeout();
}

Usage Examples

// Validating pool is useful for long-lived connections that might become stale
// Automatically validates connections before reuse

public class ValidatedClient {
    public void configureValidation() throws Exception {
        HttpClient client = new HttpClient();
        
        // Configuration for connection validation
        // Validates connections that have been idle for a certain period
        client.setIdleTimeout(30000); // 30 seconds idle timeout
        
        client.start();
        
        // Long pause between requests to demonstrate validation
        ContentResponse response1 = client.GET("https://api.example.com/data");
        System.out.println("First request: " + response1.getStatus());
        
        // Wait longer than idle timeout
        Thread.sleep(35000);
        
        // Next request will validate/recreate connection if needed
        ContentResponse response2 = client.GET("https://api.example.com/data");
        System.out.println("Second request: " + response2.getStatus());
        
        client.stop();
    }
}

Connection Pool Configuration

Per-Destination Pool Settings

public class PoolConfigurationExample {
    public void configureConnectionPools() throws Exception {
        HttpClient client = new HttpClient();
        
        // Configure maximum connections per destination
        client.setMaxConnectionsPerDestination(20);
        
        // Configure request queue size per destination
        client.setMaxRequestsQueuedPerDestination(50);
        
        // Configure connection idle timeout
        client.setIdleTimeout(60000); // 60 seconds
        
        // Configure connection establishment timeout
        client.setConnectTimeout(10000); // 10 seconds
        
        client.start();
        
        // These settings affect all connection pools for this client
        System.out.println("Max connections per destination: " + client.getMaxConnectionsPerDestination());
        System.out.println("Idle timeout: " + client.getIdleTimeout());
    }
}

Custom Connection Pool Factory

public class CustomConnectionPoolFactory {
    public static ConnectionPool createCustomPool(Destination destination, int maxConnections) {
        // Create a custom connection pool based on requirements
        
        if (destination.getScheme().equals("https") && supportsHttp2(destination)) {
            // Use multiplex pool for HTTP/2 HTTPS connections
            return new MultiplexConnectionPool(destination, maxConnections, null, 100);
        } else if (isHighVolumeDestination(destination)) {
            // Use round-robin for high-volume destinations
            return new RoundRobinConnectionPool(destination, maxConnections, null);
        } else if (isUnreliableNetwork(destination)) {
            // Use validating pool for unreliable networks
            return new ValidatingConnectionPool(destination, maxConnections, null);
        } else {
            // Default to duplex pool
            return new DuplexConnectionPool(destination, maxConnections, null);
        }
    }
    
    private static boolean supportsHttp2(Destination destination) {
        // Logic to determine if destination supports HTTP/2
        return true; // Simplified
    }
    
    private static boolean isHighVolumeDestination(Destination destination) {
        // Logic to identify high-volume destinations
        return destination.getHost().contains("api") || destination.getHost().contains("cdn");
    }
    
    private static boolean isUnreliableNetwork(Destination destination) {
        // Logic to identify destinations with unreliable connections
        return destination.getHost().contains("mobile") || destination.getHost().contains("satellite");
    }
}

Connection Pool Monitoring

Pool Statistics

public class ConnectionPoolMonitor {
    private final HttpClient client;
    
    public ConnectionPoolMonitor(HttpClient client) {
        this.client = client;
    }
    
    public void printPoolStatistics() {
        // Note: Direct access to connection pools requires internal APIs
        // This is conceptual - actual implementation may vary
        
        System.out.println("Connection Pool Statistics:");
        System.out.println("Max connections per destination: " + client.getMaxConnectionsPerDestination());
        System.out.println("Current destinations: " + getDestinationCount());
        
        // Per-destination statistics would require accessing internal destination manager
        printDestinationStats();
    }
    
    private void printDestinationStats() {
        // Conceptual implementation for monitoring
        System.out.println("Destination Statistics:");
        System.out.println("  api.example.com: 5 active, 3 idle connections");
        System.out.println("  cdn.example.com: 2 active, 8 idle connections");
    }
    
    private int getDestinationCount() {
        // Would access internal destination manager
        return 0; // Placeholder
    }
    
    public void scheduleMonitoring(ScheduledExecutorService scheduler) {
        scheduler.scheduleAtFixedRate(this::printPoolStatistics, 0, 30, TimeUnit.SECONDS);
    }
}

Connection Lifecycle Monitoring

public class ConnectionLifecycleMonitor {
    public void monitorConnections(HttpClient client) {
        // Add request listeners to monitor connection usage
        client.getRequestListeners().addListener(new Request.Listener() {
            @Override
            public void onBegin(Request request) {
                Connection connection = request.getConnection();
                if (connection != null) {
                    System.out.println("Request started on connection: " + connection);
                }
            }
            
            @Override
            public void onSuccess(Request request) {
                Connection connection = request.getConnection();
                if (connection != null) {
                    System.out.println("Request completed on connection: " + connection);
                }
            }
        });
    }
}

Advanced Pool Management

Pool Preheating

public class PoolPreheating {
    public void preheatConnections(HttpClient client, String... urls) throws Exception {
        List<CompletableFuture<Void>> preheatFutures = new ArrayList<>();
        
        for (String url : urls) {
            // Make lightweight requests to establish connections
            CompletableFuture<Void> future = client.newRequest(url)
                .method(HttpMethod.HEAD) // Use HEAD to minimize data transfer
                .send()
                .thenApply(response -> null); // Convert to Void
                
            preheatFutures.add(future);
        }
        
        // Wait for all preheat requests to complete
        CompletableFuture.allOf(preheatFutures.toArray(new CompletableFuture[0]))
            .get(30, TimeUnit.SECONDS);
            
        System.out.println("Connection pools preheated for " + urls.length + " destinations");
    }
}

// Usage
PoolPreheating preheater = new PoolPreheating();
preheater.preheatConnections(client, 
    "https://api.example.com",
    "https://cdn.example.com", 
    "https://auth.example.com"
);

Dynamic Pool Sizing

public class DynamicPoolManager {
    private final HttpClient client;
    private final Map<String, Integer> destinationLoad;
    
    public DynamicPoolManager(HttpClient client) {
        this.client = client;
        this.destinationLoad = new ConcurrentHashMap<>();
    }
    
    public void adjustPoolSizes() {
        destinationLoad.forEach((destination, load) -> {
            int recommendedSize = calculateOptimalPoolSize(load);
            adjustPoolSize(destination, recommendedSize);
        });
    }
    
    private int calculateOptimalPoolSize(int load) {
        // Calculate optimal pool size based on load
        if (load > 100) return 50;
        if (load > 50) return 25;
        if (load > 10) return 10;
        return 5;
    }
    
    private void adjustPoolSize(String destination, int size) {
        // Conceptual - actual implementation would require internal APIs
        System.out.println("Adjusting pool size for " + destination + " to " + size);
    }
    
    public void recordRequest(String destination) {
        destinationLoad.merge(destination, 1, Integer::sum);
    }
    
    public void scheduleOptimization(ScheduledExecutorService scheduler) {
        scheduler.scheduleAtFixedRate(this::adjustPoolSizes, 0, 60, TimeUnit.SECONDS);
    }
}

Connection Pool Best Practices

Optimal Configuration

public class PoolBestPractices {
    public HttpClient createOptimalClient() throws Exception {
        HttpClient client = new HttpClient();
        
        // Conservative connection limits to avoid overwhelming servers
        client.setMaxConnectionsPerDestination(20);
        client.setMaxRequestsQueuedPerDestination(100);
        
        // Reasonable timeouts
        client.setConnectTimeout(10000); // 10 seconds
        client.setIdleTimeout(60000);    // 60 seconds
        
        // Enable connection keep-alive
        client.setTCPNoDelay(true);
        
        // Configure for HTTP/2 when available
        client.setProtocols(List.of("h2", "http/1.1"));
        
        client.start();
        return client;
    }
    
    public void demonstrateEfficientUsage(HttpClient client) throws Exception {
        // Reuse client across multiple requests for connection pooling benefits
        List<CompletableFuture<ContentResponse>> futures = new ArrayList<>();
        
        // Make multiple requests to same destination - will reuse connections
        for (int i = 0; i < 10; i++) {
            CompletableFuture<ContentResponse> future = client.newRequest("https://api.example.com/data/" + i).send();
            futures.add(future);
        }
        
        // Process responses as they complete
        for (CompletableFuture<ContentResponse> future : futures) {
            future.thenAccept(response -> {
                System.out.println("Response: " + response.getStatus());
                // Connection automatically returned to pool after response processing
            });
        }
        
        // Don't stop client until all operations are complete
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
    }
}

Resource Management

public class ResourceManagedClient implements AutoCloseable {
    private final HttpClient client;
    
    public ResourceManagedClient() throws Exception {
        this.client = new HttpClient();
        configureClient();
        client.start();
    }
    
    private void configureClient() {
        // Optimize for connection reuse
        client.setMaxConnectionsPerDestination(15);
        client.setIdleTimeout(30000);
        
        // Add shutdown hook for graceful cleanup
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                close();
            } catch (Exception e) {
                System.err.println("Error during client shutdown: " + e.getMessage());
            }
        }));
    }
    
    public ContentResponse get(String url) throws Exception {
        return client.GET(url);
    }
    
    @Override
    public void close() throws Exception {
        // Graceful shutdown - allows existing requests to complete
        client.stop();
    }
}

// Usage with try-with-resources
try (ResourceManagedClient client = new ResourceManagedClient()) {
    ContentResponse response = client.get("https://api.example.com/data");
    System.out.println("Response: " + response.getStatus());
} // Automatically closes and cleans up connection pools

Install with Tessl CLI

npx tessl i tessl/maven-org-eclipse-jetty--jetty-client

docs

authentication.md

connection-pooling.md

content-management.md

http-operations.md

index.md

proxy-configuration.md

request-configuration.md

response-processing.md

tile.json