package org.distributeme.core.failing; import org.configureme.ConfigurationManager; import org.distributeme.core.ClientSideCallContext; import org.distributeme.core.exception.ServiceUnavailableException; import org.distributeme.core.routing.ConfigurableRouter; import org.distributeme.core.routing.Constants; import org.distributeme.core.routing.GenericRouterConfiguration; import org.distributeme.core.routing.RouterConfigurationObserver; import org.distributeme.core.routing.blacklisting.BlacklistingStrategy; import org.distributeme.core.routing.blacklisting.DefaultBlacklistingStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Created by hpemoeller on 4/10/17. */ public class FailoverAndReturnWithConfigurableBlacklisting extends FailoverAndReturn implements ConfigurableRouter, RouterConfigurationObserver { private static final Logger LOG = LoggerFactory.getLogger(Constants.ROUTING_LOGGER_NAME); private GenericRouterConfiguration configuration = new GenericRouterConfiguration(); private BlacklistingStrategy blacklistingStrategy = new DefaultBlacklistingStrategy(); @Override protected long getFailbackTimeout() { return configuration.getBlacklistTime(); } @Override public void setConfigurationName(String serviceId, String configurationName) { setServiceId(serviceId); configuration.addRouterConfigurationObserver(this); try{ ConfigurationManager.INSTANCE.configureAs(configuration, configurationName); }catch(IllegalArgumentException e){ throw new IllegalStateException("Can't configure router and this leaves us in undefined state, probably configuration not found: "+configurationName, e); } } @Override public void routerConfigurationInitialChange(GenericRouterConfiguration configuration) { //not needed } @Override public void routerConfigurationFollowupChange(GenericRouterConfiguration configuration) { updateRouterConfiguration(configuration); } @Override public void routerConfigurationChange(GenericRouterConfiguration configuration) { updateRouterConfiguration(configuration); } @Override public FailDecision callFailed(ClientSideCallContext context) { blacklistingStrategy.notifyCallFailed(context); getRoutingStats(context.getServiceId()).addFailedCall(); if (nextNodeIsBlacklisted(context) && !isOverrideBlacklistIfAllBlacklisted()){ getRoutingStats(context.getServiceId()).addFailedCall(); throw new ServiceUnavailableException(context.getServiceId() + " and " + createServiceIdForNextServiceCall(context) + " are Blacklisted!"); } return retryOneceOnService(createServiceIdForNextServiceCall(context)); } private boolean isOverrideBlacklistIfAllBlacklisted() { return getConfiguration().isOverrideBlacklistIfAllBlacklisted(); } private boolean nextNodeIsBlacklisted(ClientSideCallContext context) { return blacklistingStrategy.isBlacklisted(createServiceIdForNextServiceCall(context)); } private String createServiceIdForNextServiceCall(ClientSideCallContext context) { String targetService = context.getServiceId() + getSuffix(); if (context.getServiceId().contains(getSuffix())){ targetService = context.getServiceId().replace(getSuffix(),""); } getRoutingStats(targetService).addRequestRoutedTo(); return targetService; } private FailDecision retryOneceOnService(String targetService) { getRoutingStats(targetService).addRequestRoutedTo(); FailDecision ret = FailDecision.retryOnce(); ret.setTargetService(targetService); return ret; } @Override public String getServiceIdForCall(ClientSideCallContext callContext) { if (blacklistingStrategy.isBlacklisted(callContext.getServiceId())){ getRoutingStats(callContext.getServiceId()).addBlacklisted(); return createServiceIdForNextServiceCall(callContext); } getRoutingStats(callContext.getServiceId()).addRequestRoutedTo(); return callContext.getServiceId(); } @Override protected String getSuffix() { return "_failover"; } private void updateRouterConfiguration(GenericRouterConfiguration configuration) { this.configuration = configuration; if(getConfiguration().getBlacklistStrategyClazz() != null) { try { blacklistingStrategy = (BlacklistingStrategy)Class.forName(getConfiguration().getBlacklistStrategyClazz()).newInstance(); } catch (Exception e) { LOG.error("Could not initialize black listing strategy " + getConfiguration().getBlacklistStrategyClazz() + " using: " + blacklistingStrategy.getClass().getName(), e); } } blacklistingStrategy.setConfiguration(getConfiguration()); } GenericRouterConfiguration getConfiguration() { return configuration; } BlacklistingStrategy getBlacklistingStrategy() { return blacklistingStrategy; } void setBlacklistingStrategy(BlacklistingStrategy blacklistingStrategy) { this.blacklistingStrategy = blacklistingStrategy; } void setConfiguration(GenericRouterConfiguration configuration) { this.configuration = configuration; } }