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

org.fishwife.jrugged.DefaultFailureInterpreter Maven / Gradle / Ivy

/* DefaultFailureInterpreter.java
 * 
 * Copyright 2009-2012 Comcast Interactive Media, LLC.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.fishwife.jrugged;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Trips a {@link CircuitBreaker} if the number of failures in a given
 * time window exceed a specified tolerance.  By default, all {@link
 * Throwable} occurrences will be considered failures.
 */
public final class DefaultFailureInterpreter implements FailureInterpreter {

    private Set> ignore = new HashSet>();
    private int limit = 0;
    private long windowMillis = 0;

	private WindowedEventCounter counter;
	
	@SuppressWarnings("unchecked")
	private static Class[] defaultIgnore = 
		new Class[0];

    /**
     * Default constructor. Any {@link Throwable} will cause the breaker to trip.
     */
    public DefaultFailureInterpreter() {
		setIgnore(defaultIgnore);
	}

    /**
     * Constructor that allows a tolerance for a certain number of
     * failures within a given window of time without tripping.
     * @param limit the number of failures that will be tolerated
     *   (i.e. the number of failures has to be strictly greater
     *   than this number in order to trip the breaker). For
     *   example, if the limit is 3, the fourth failure during
     *   the window will cause the breaker to trip.
     * @param windowMillis length of the window in milliseconds
     */
	public DefaultFailureInterpreter(int limit, long windowMillis) {
		setIgnore(defaultIgnore);
		setLimit(limit);
		setWindowMillis(windowMillis);
		initCounter();
	}

    /**
     * Constructor where we specify certain {@link Throwable} classes
     * that will be ignored by the breaker and not be treated as
     * failures (they will be passed through transparently without 
     * causing the breaker to trip).
     * @param ignore an array of {@link Throwable} classes that will
     *   be ignored. Any given Throwable that is a
     *   subclass of one of these classes will be ignored. 
     */
	public DefaultFailureInterpreter(Class[] ignore) {
		setIgnore(ignore);
	}

    /**
     * Constructor where we specify tolerance and a set of ignored failures.
     *
     * @param ignore an array of {@link Throwable} classes that will
     *   be ignored. Any given Throwable that is a
     *   subclass of one of these classes will be ignored. 
     * @param limit the number of failures that will be tolerated
     *   (i.e. the number of failures has to be strictly greater
     *   than this number in order to trip the breaker). For
     *   example, if the limit is 3, the fourth failure during 
     *   the window will cause the breaker to trip.
     * @param windowMillis length of the window in milliseconds
     */
	public DefaultFailureInterpreter(Class[] ignore,
									 int limit, long windowMillis) {
		setIgnore(ignore);
		setLimit(limit);
		setWindowMillis(windowMillis);
		initCounter();
	}

    private boolean hasWindowConditions() {
        return this.limit > 0 && this.windowMillis > 0;
    }
	
	public boolean shouldTrip(Throwable cause) {
		for(Class clazz : ignore) {
			if (clazz.isInstance(cause)) {
				return false;
			}
		}

		// if Exception is of specified type, and window conditions exist,
		// keep circuit open unless exception threshold has passed
		if (hasWindowConditions()) {
			counter.mark();
			// Trip if the exception count has passed the limit
			return (counter.tally() > limit);
		}
		
		return true;
	}
	
	private void initCounter() {
		if (hasWindowConditions()) {
			int capacity = limit + 1;
			if (counter == null) {
				this.counter = new WindowedEventCounter(capacity,windowMillis);
			} else {
				if (capacity != counter.getCapacity()) {
					counter.setCapacity(capacity);
				}

				if (windowMillis != counter.getWindowMillis()) {
					counter.setWindowMillis(windowMillis);
				}
			}
		} else {
			// we're not under windowConditions, no counter needed
			counter = null;
		}
	}

    /**
     * Returns the set of currently ignored {@link Throwable} classes.
     * @return {@link Set}
     */
    public Set> getIgnore(){
        return this.ignore;
    }

    /**
     * Specifies an array of {@link Throwable} classes to ignore. These will not
     * be considered failures.
     * @param ignore array of {@link Class} objects
     */
    public synchronized void setIgnore(Class[] ignore) {
		this.ignore = new HashSet>(Arrays.asList(ignore));
    }

    /**
     * Returns the current number of failures within the window that will be tolerated
     * without tripping the breaker.
     * @return int
     */
    public int getLimit(){
        return this.limit;
    }

    /**
     * Specifies the number of tolerated failures within the
     * configured time window. If limit is set to n then the
     * (n+1)th failure will trip the breaker.  Mutating the
     * limit at runtime can reset previous failure counts.
     * @param limit int
     */
    public void setLimit(int limit) {
        this.limit=limit;
        initCounter();
    }

    /**
     * Returns the length of the currently configured tolerance window
     * in milliseconds.
     * @return long
     */
    public long getWindowMillis(){
        return this.windowMillis;
    }

    /**
     * Specifies the length of the tolerance window in milliseconds.
     * @param windowMillis long
     */
    public void setWindowMillis(long windowMillis) {
        this.windowMillis=windowMillis;
        initCounter();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy