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

com.netflix.hystrix.HystrixObservableCommand Maven / Gradle / Ivy

There is a newer version: 1.5.18
Show newest version
/**
 * Copyright 2012 Netflix, Inc.
 * 
 * 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 com.netflix.hystrix;

import rx.Observable;

import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;

/**
 * Used to wrap code that will execute potentially risky functionality (typically meaning a service call over the network)
 * with fault and latency tolerance, statistics and performance metrics capture, circuit breaker and bulkhead functionality.
 * This command should be used for a purely non-blocking call pattern. The caller of this command will be subscribed to the Observable returned by the run() method.
 * 
 * @param 
 *            the return type
 * 
 * @ThreadSafe
 */
public abstract class HystrixObservableCommand extends AbstractCommand implements HystrixObservable, HystrixInvokableInfo {

    /**
     * Construct a {@link HystrixObservableCommand} with defined {@link HystrixCommandGroupKey}.
     * 

* The {@link HystrixCommandKey} will be derived from the implementing class name. * * @param group * {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixObservableCommand} objects. *

* The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace with, * common business purpose etc. */ protected HystrixObservableCommand(HystrixCommandGroupKey group) { // use 'null' to specify use the default this(new Setter(group)); } /** * * Overridden to true so that all onNext emissions are captured * * @return if onNext events should be reported on * This affects {@link HystrixRequestLog}, and {@link HystrixEventNotifier} currently. Metrics/Hooks later */ @Override protected boolean shouldOutputOnNextEvents() { return true; } @Override protected String getFallbackMethodName() { return "resumeWithFallback"; } @Override protected boolean isFallbackUserDefined() { Boolean containsFromMap = commandContainsFallback.get(commandKey); if (containsFromMap != null) { return containsFromMap; } else { Boolean toInsertIntoMap; try { getClass().getDeclaredMethod("resumeWithFallback"); toInsertIntoMap = true; } catch (NoSuchMethodException nsme) { toInsertIntoMap = false; } commandContainsFallback.put(commandKey, toInsertIntoMap); return toInsertIntoMap; } } @Override protected boolean commandIsScalar() { return false; } /** * Construct a {@link HystrixObservableCommand} with defined {@link Setter} that allows injecting property and strategy overrides and other optional arguments. *

* NOTE: The {@link HystrixCommandKey} is used to associate a {@link HystrixObservableCommand} with {@link HystrixCircuitBreaker}, {@link HystrixCommandMetrics} and other objects. *

* Do not create multiple {@link HystrixObservableCommand} implementations with the same {@link HystrixCommandKey} but different injected default properties as the first instantiated will win. *

* Properties passed in via {@link Setter#andCommandPropertiesDefaults} are cached for the given {@link HystrixCommandKey} for the life of the JVM * or until {@link Hystrix#reset()} is called. Dynamic properties allow runtime changes. Read more on the Hystrix Wiki. * * @param setter * Fluent interface for constructor arguments */ protected HystrixObservableCommand(Setter setter) { // use 'null' to specify use the default this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null); } /** * Allow constructing a {@link HystrixObservableCommand} with injection of most aspects of its functionality. *

* Some of these never have a legitimate reason for injection except in unit testing. *

* Most of the args will revert to a valid default if 'null' is passed in. */ HystrixObservableCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults, HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore, HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) { super(group, key, threadPoolKey, circuitBreaker, threadPool, commandPropertiesDefaults, threadPoolPropertiesDefaults, metrics, fallbackSemaphore, executionSemaphore, propertiesStrategy, executionHook); } /** * Fluent interface for arguments to the {@link HystrixObservableCommand} constructor. *

* The required arguments are set via the 'with' factory method and optional arguments via the 'and' chained methods. *

* Example: *

 {@code
     *  Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GroupName"))
                .andCommandKey(HystrixCommandKey.Factory.asKey("CommandName"))
                .andEventNotifier(notifier);
     * } 
* * @NotThreadSafe */ final public static class Setter { protected final HystrixCommandGroupKey groupKey; protected HystrixCommandKey commandKey; protected HystrixThreadPoolKey threadPoolKey; protected HystrixCommandProperties.Setter commandPropertiesDefaults; protected HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults; /** * Setter factory method containing required values. *

* All optional arguments can be set via the chained methods. * * @param groupKey * {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixObservableCommand} objects. *

* The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace * with, * common business purpose etc. */ protected Setter(HystrixCommandGroupKey groupKey) { this.groupKey = groupKey; // default to using SEMAPHORE for ObservableCommand commandPropertiesDefaults = setDefaults(HystrixCommandProperties.Setter()); } /** * Setter factory method with required values. *

* All optional arguments can be set via the chained methods. * * @param groupKey * {@link HystrixCommandGroupKey} used to group together multiple {@link HystrixObservableCommand} objects. *

* The {@link HystrixCommandGroupKey} is used to represent a common relationship between commands. For example, a library or team name, the system all related commands interace * with, * common business purpose etc. */ public static Setter withGroupKey(HystrixCommandGroupKey groupKey) { return new Setter(groupKey); } /** * @param commandKey * {@link HystrixCommandKey} used to identify a {@link HystrixObservableCommand} instance for statistics, circuit-breaker, properties, etc. *

* By default this will be derived from the instance class name. *

* NOTE: Every unique {@link HystrixCommandKey} will result in new instances of {@link HystrixCircuitBreaker}, {@link HystrixCommandMetrics} and {@link HystrixCommandProperties}. * Thus, * the number of variants should be kept to a finite and reasonable number to avoid high-memory usage or memory leacks. *

* Hundreds of keys is fine, tens of thousands is probably not. * @return Setter for fluent interface via method chaining */ public Setter andCommandKey(HystrixCommandKey commandKey) { this.commandKey = commandKey; return this; } /** * Optional * * @param commandPropertiesDefaults * {@link HystrixCommandProperties.Setter} with property overrides for this specific instance of {@link HystrixObservableCommand}. *

* See the {@link HystrixPropertiesStrategy} JavaDocs for more information on properties and order of precedence. * @return Setter for fluent interface via method chaining */ public Setter andCommandPropertiesDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) { this.commandPropertiesDefaults = setDefaults(commandPropertiesDefaults); return this; } private HystrixCommandProperties.Setter setDefaults(HystrixCommandProperties.Setter commandPropertiesDefaults) { if (commandPropertiesDefaults.getExecutionIsolationStrategy() == null) { // default to using SEMAPHORE for ObservableCommand if the user didn't set it commandPropertiesDefaults.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE); } return commandPropertiesDefaults; } } /** * Implement this method with code to be executed when {@link #observe()} or {@link #toObservable()} are invoked. * * @return R response type */ protected abstract Observable construct(); /** * If {@link #observe()} or {@link #toObservable()} fails in any way then this method will be invoked to provide an opportunity to return a fallback response. *

* This should do work that does not require network transport to produce. *

* In other words, this should be a static or cached result that can immediately be returned upon failure. *

* If network traffic is wanted for fallback (such as going to MemCache) then the fallback implementation should invoke another {@link HystrixObservableCommand} instance that protects against * that network * access and possibly has another level of fallback that does not involve network access. *

* DEFAULT BEHAVIOR: It throws UnsupportedOperationException. * * @return R or UnsupportedOperationException if not implemented */ protected Observable resumeWithFallback() { return Observable.error(new UnsupportedOperationException("No fallback available.")); } @Override final protected Observable getExecutionObservable() { return construct(); } @Override final protected Observable getFallbackObservable() { return resumeWithFallback(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy