package com.dianping.pigeon.remoting.invoker.cluster; import com.dianping.pigeon.log.Logger; import com.dianping.pigeon.log.LoggerLoader; import com.dianping.pigeon.remoting.common.domain.InvocationRequest; import com.dianping.pigeon.remoting.common.domain.InvocationResponse; import com.dianping.pigeon.remoting.common.exception.NetworkException; import com.dianping.pigeon.remoting.common.process.ServiceInvocationHandler; import com.dianping.pigeon.remoting.common.util.Constants; import com.dianping.pigeon.remoting.invoker.Client; import com.dianping.pigeon.remoting.invoker.ClientManager; import com.dianping.pigeon.remoting.invoker.config.InvokerConfig; import com.dianping.pigeon.remoting.invoker.domain.InvokerContext; import com.dianping.pigeon.remoting.invoker.exception.RemoteInvocationException; import com.dianping.pigeon.remoting.invoker.exception.RequestTimeoutException; import com.dianping.pigeon.remoting.invoker.exception.ServiceUnavailableException; import com.dianping.pigeon.remoting.invoker.util.InvokerUtils; public class FailfastCluster implements Cluster { private ClientManager clientManager = ClientManager.getInstance(); private static final Logger logger = LoggerLoader.getLogger(FailfastCluster.class); @Override public InvocationResponse invoke(ServiceInvocationHandler handler, InvokerContext invocationContext) throws Throwable { InvokerConfig<?> invokerConfig = invocationContext.getInvokerConfig(); InvocationRequest request = InvokerUtils.createRemoteCallRequest(invocationContext, invokerConfig); boolean timeoutRetry = invokerConfig.isTimeoutRetry(); if (!timeoutRetry) { Client remoteClient = clientManager.getClient(invokerConfig, request, null); invocationContext.setClient(remoteClient); try { return handler.handle(invocationContext); } catch (NetworkException e) { remoteClient = clientManager.getClient(invokerConfig, request, null); invocationContext.setClient(remoteClient); return handler.handle(invocationContext); } } else { int retry = invokerConfig.getRetries(invocationContext.getMethodName()); RequestTimeoutException lastError = null; int maxInvokeTimes = retry + 1; int invokeTimes = 0; for (int index = 0; index < maxInvokeTimes; index++) { Client clientSelected = null; try { clientSelected = clientManager.getClient(invokerConfig, request, null); } catch (ServiceUnavailableException e) { if (invokeTimes > 0) { logger.error("Invoke method[" + invocationContext.getMethodName() + "] on service[" + invokerConfig.getUrl() + "] failed with " + invokeTimes + " times"); throw lastError; } else { throw e; } } try { invokeTimes++; invocationContext.setClient(clientSelected); InvocationResponse response = null; try { response = handler.handle(invocationContext); } catch (NetworkException e) { clientSelected = clientManager.getClient(invokerConfig, request, null); invocationContext.setClient(clientSelected); response = handler.handle(invocationContext); logger.info("Retry while network exception:" + e.getMessage()); } if (lastError != null) { logger.warn("Retry method[" + invocationContext.getMethodName() + "] on service[" + invokerConfig.getUrl() + "] succeed after " + invokeTimes + " times, last failed error: " + lastError.getMessage(), lastError); } return response; } catch (RequestTimeoutException e) { lastError = e; } } if (lastError != null) { throw lastError; } else { throw new RemoteInvocationException( "Invoke method[" + invocationContext.getMethodName() + "] on service[" + invokerConfig.getUrl() + "] failed with " + invokeTimes + " times, last error: " + (lastError != null ? lastError.getMessage() : ""), lastError != null && lastError.getCause() != null ? lastError.getCause() : lastError); } } } @Override public String getName() { return Constants.CLUSTER_FAILFAST; } }