Plugins

Matt Jacobs edited this page Feb 7, 2017 · 15 revisions

Contents

  1. Plugins
  2. Plugin Types
    1. Event Notifier
    2. Metrics Publisher
    3. Properties Strategy
    4. Concurrency Strategy
    5. Command Execution Hook
  3. How to Use
  4. Abstract vs. Interface

Plugins

You can modify the behavior of Hystrix, or add additional behavior to it, by implementing plugins.

You register these plugins by means of the HystrixPlugins service. Hystrix will then apply them to all HystrixCommand, HystrixObservableCommand, and HystrixCollapser implementations, overriding all others.

Plugin Types

Following are introductions to each of the different plugins that you can implement (the Javadocs contain more detail):

Event Notifier

Events that occur during HystrixCommand and HystrixObservableCommand execution are trigged on the HystrixEventNotifier to give an opportunity for alerting and statistics-collection.

Metrics Publisher

Each instance of metrics being captured (such as for all HystrixCommands with a given HystrixCommandKey) will ask the HystrixMetricsPublisher for an implementation and initialize it.

This gives the implementation the opportunity to receive the metrics data objects and start a background process for doing something with the metrics such as publishing them to a persistent store.

The default implementation does not publish them anywhere.

If you wish to use Servo, which is an in-memory system that supports various mechanisms of retrieving the data such as through pollers or JMX, please see the documentation at https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-servo-metrics-publisher

Properties Strategy

If you implement a custom HystrixPropertiesStrategy, this gives you full control over how properties are defined for the system.

The default implementation uses Archaius.

Concurrency Strategy

Hystrix uses implementations of ThreadLocal, Callable, Runnable, ThreadPoolExecutor, and BlockingQueue as part its thread isolation and request-scoped functionality.

By default Hystrix has implementations that work “out of the box” but many environments (including Netflix) desire the use of alternatives so this plugin allows injecting custom implementations or decorating behavior.

You can implement the HystrixConcurrencyStrategy class with the following:

  • The getThreadPool() and getBlockingQueue() methods are straightforward options that inject the implementation of your choice, or just a decorated version with extra logging and metrics.

  • The wrapCallable() method allows you to decorate every Callable executed by Hystrix. This can be essential to systems that rely upon ThreadLocal state for application functionality. The wrapping Callable can capture and copy state from parent to child thread as needed.

  • The getRequestVariable() method expects an implementation of HystrixRequestVariable<T> that functions like a ThreadLocal except scoped to the request — available on all threads within the request. Generally it will be easier and sufficient to just use the HystrixRequestContext with its own default implementation of HystrixRequestVariable.

Command Execution Hook

A HystrixCommandExecutionHook implementation gives you access to the execution lifecycle of a HystrixInvokable (HystrixCommand or HystrixObservableCommand) so that you can inject behavior, logging, override responses, alter thread state, etc. You do this by overriding one or more of the following hooks:

HystrixCommandExecutionHook method when Hystrix calls the method
onStart before the HystrixInvokable begins executing
onEmit whenever the HystrixInvokable emits a value
onError if the HystrixInvokable fails with an exception
onSuccess if the HystrixInvokable completes successfully
onThreadStart at the start of thread execution if the HystrixInvokable is a HystrixCommand executed using the THREAD ExecutionIsolationStrategy
onThreadComplete at the completion of thread execution if the HystrixInvokable is a HystrixCommand executed using the THREAD ExecutionIsolationStrategy
onExecutionStart when the user-defined execution method in the HystrixInvokable begins
onExecutionEmit whenever the user-defined execution method in the HystrixInvokable emits a value
onExecutionError when the user-defined execution method in the HystrixInvokable fails with an exception
onExecutionSuccess when the user-defined execution method in the HystrixInvokable completes successfully
onFallbackStart if the HystrixInvokable attempts to call the fallback method
onFallbackEmit whenever the fallback method in the HystrixInvokable emits a value
onFallbackError if the fallback method in the HystrixInvokable fails with an exception or does not exist when a call attempt is made
onFallbackSuccess if the fallback method in the HystrixInvokable completes successfully
onCacheHit if the response to the HystrixInvokable is found in the HystrixRequestCache

How to Use

When you invoke a HystrixCommand for the first time, it begins to access functionality that is governed by plugins. Since you cannot swap out plugins at runtime, the plugins that the HystrixCommand uses during this first invocation become the plugins that the HystrixCommand will use for the duration of the JVM run.

If you registered a plugin in Archaius, then that plugin implementation is used. If not, then Hystrix chooses a default plugin. Here’s an example of how to use Archaius for this purpose: https://github.com/eirslett/pull-request-illustration.

If you wish to register a plugin before you invoke the HystrixCommand for the first time, you may do so with code like the following:

HystrixPlugins.getInstance().registerEventNotifier(ACustomHystrixEventNotifierDefaultStrategy.getInstance());

Abstract vs. Interface

Each of the plugins shown above exposes the base as an abstract class to be extended rather than as an interface to be implemented.

This is for 2 reasons:

1) Default Behavior

You only need to override those methods that you need to customize. You can retain the default behavior of other methods by not altering them.

Each method implementation is intended to be stand-alone and not have side effects or state so when you override one method without changing another this should not have implications.

Extension is accomplished via abstract base classes primarily for the next reason...

2) Library Maintenance

As Hystrix evolves, each of these plugins may gain new methods as new functionality is added or new things are found that need to be customized by users.

If Hystrix used an interface for this purpose, it would either require a new interface each time new functionality was added (basically an interface per method) or it would necessitate breaking changes for anybody who has implemented the interface. This problem will go away in Java 8 when “default methods” will exist on interfaces, but it will be a while before that is available and this library can choose Java 8 as the minimum supported JDK version.

Hystrix uses abstract base classes so that new optional methods can be added in point releases instead of major releases without breaking existing implementations.