All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.segmentio.safeclient.AsyncHttpBatchedOperation Maven / Gradle / Ivy

package com.github.segmentio.safeclient;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ning.http.client.AsyncCompletionHandler;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.Request;
import com.ning.http.client.Response;

public abstract class AsyncHttpBatchedOperation 
	extends BatchedOperation {

	private static final Logger logger = 
			LoggerFactory.getLogger(AsyncHttpBatchedOperation.class);
	
    private AsyncHttpClient asyncHttpClient;
    private int maximumOutstandingConnections;
    
    private AtomicInteger outstanding;
    
    public AsyncHttpBatchedOperation() {
    	
    	maximumOutstandingConnections = 100;
    	outstanding = new AtomicInteger(0);
    	
    	asyncHttpClient = new AsyncHttpClient(
	    	
    		new AsyncHttpClientConfig.Builder()
	    		.setMaxRequestRetry(1)
	    		.setIdleConnectionTimeoutInMs(30 * 1000)
	    		.setMaximumConnectionsTotal(maximumOutstandingConnections)
	    		.setAllowPoolingConnection(true)
	    		.build()
	    );

    	if (maximumOutstandingConnections < 1) 
    		throw new IllegalArgumentException("Outstanding connections must be greater than 0.");
    }
    
    public AsyncHttpBatchedOperation(AsyncHttpClient client) {
    	
    	this.asyncHttpClient = client;
    	
    	maximumOutstandingConnections = client.getConfig().getMaxTotalConnections();
    	outstanding = new AtomicInteger(0);
    	
    	if (maximumOutstandingConnections < 1) 
    		throw new IllegalArgumentException("Outstanding connections must be greater than 0.");
    }
	
	public abstract Request buildRequest(List batch);
	
	@Override
	public boolean canFlush() {
		return outstanding.get() < maximumOutstandingConnections;
	}
	
	@Override
	public void performFlush(final List batch) {
	
		Request request = buildRequest(batch);
		
		statistics.update("Request Body Size (bytes)", request.getContentLength());
		
		outstanding.incrementAndGet();
		
		try {
			
			final long start = System.currentTimeMillis(); 
			
			asyncHttpClient.executeRequest(request, new AsyncCompletionHandler() {

				@Override
				public Response onCompleted(Response response) throws Exception {
					
					outstanding.decrementAndGet();
					
					long duration = System.currentTimeMillis() - start;
					statistics.update("Request Duration (ms)", duration);
					
					int statusCode = response.getStatusCode(); 
					if (statusCode == 200) {
						statistics.update("Successful Requests", 1);
					} else {
						if (errorLoggingRateLimit.canPerform()) {
							logger.error("Response [code = " + statusCode + 
									"]. Response = " + response.getResponseBody());
						}
						statistics.update("Failed Requests", 1);
					}
					
					onFlush(batch, response);
					
					return response;
				}
				
			});
			
		} catch (IOException e) {
			
			if (errorLoggingRateLimit.canPerform()) {
				logger.error("Async HTTP flush failed.", e);
			}
			
			outstanding.decrementAndGet();
			
		}
	}
	
	/**
	 * Called when a flush occurs on a batch
	 * @param batch
	 * @param response
	 */
	public void onFlush(List batch, Response response) {
		// do nothing
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy