Copying current request information into Feign interceptor with Hystrix enabled

Not so long ago I came across a problem which was related to localization in a microservices architecture which was using Feign for internal service communication.

The idea was that if an incoming request has an Accept-Language  header, I should pass it over with every Feign request in order to have the locale information in every single service throughout the system. For this, I wanted to use RequestInterceptor , but luckily I was also using Hystrix enabled in the services.

The code I had in my interceptor is similar to the following:

public class LanguageRequestInterceptor implements RequestInterceptor {
    private static final String ACCEPT_LANGUAGE_HEADER = "Accept-Language";

    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
        HttpServletRequest request = requestAttributes.getRequest();
        if (request == null) {
        String language = request.getHeader(ACCEPT_LANGUAGE_HEADER);
        if (language == null) {
        requestTemplate.header(ACCEPT_LANGUAGE_HEADER, language);

Now what I experienced is that localization was simply not working. When I debugged this piece of code, it turned out that the I cannot access the current request bound to the thread. After a little bit of investigation I realized that Hystrix was playing me. By default, Hystrix is executing the Feign requests in a separate thread, meaning that the original request information will not be available as it’s stored in a ThreadLocal  variable. Unless you have some custom code to copy it.

So this is what I did:

public class RequestContextHolderHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
    private HystrixConcurrencyStrategy delegate;

    public RequestContextHolderHystrixConcurrencyStrategy() {
        this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
        HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook();
        HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
        HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
        HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();

    public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
        return delegate != null ? delegate.getBlockingQueue(maxQueueSize) : super.getBlockingQueue(maxQueueSize);

    public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
        return delegate != null ? delegate.getRequestVariable(rv) : super.getRequestVariable(rv);

    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixProperty<Integer> corePoolSize,
                                            HystrixProperty<Integer> maximumPoolSize, HystrixProperty<Integer> keepAliveTime, TimeUnit unit,
                                            BlockingQueue<Runnable> workQueue) {
        return delegate != null ? delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue)
                : super.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);

    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey, HystrixThreadPoolProperties threadPoolProperties) {
        return delegate != null ? delegate.getThreadPool(threadPoolKey, threadPoolProperties) : super.getThreadPool(threadPoolKey, threadPoolProperties);

    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        RequestContextHolderCallable<T> delegatingCallable = new RequestContextHolderCallable<>(callable, requestAttributes);
        return delegate != null ? delegate.wrapCallable(delegatingCallable) : super.wrapCallable(delegatingCallable);

The important method is the wrapCallable which is basically overridden to propagate the original request attributes to the new thread. This is how the RequestContextHolderCallable  looks like:

public class RequestContextHolderCallable<V> implements Callable<V> {
    private final Callable<V> delegate;
    private final RequestAttributes originalRequestAttributes;

    public RequestContextHolderCallable(Callable<V> delegate, RequestAttributes originalRequestAttributes) {
        this.delegate = delegate;
        this.originalRequestAttributes = originalRequestAttributes;

    public V call() throws Exception {
        RequestAttributes currentRequestAttributes = RequestContextHolder.getRequestAttributes();
        try {
        } finally {

After starting the application, the locale will be propagated correctly.

The example project can be found on my GitHub page.

6 Replies to “Copying current request information into Feign interceptor with Hystrix enabled”

    1. Hey, that will definitely solve the issue but bring in others. Semaphore isolation means that the same thread will be reused and Hystrix will use a semaphore to separate contexts which implies that in a system which needs high throughput, most probably it will not be as effective as it should be.

  1. Hi Arnold, I read your another post that you explain how to propagate the request but in that post you not tell me the trick in this current post and I lost a lot of time to understand why my request was returning null. I change to Semaphore and I didn’t like that approach. Thanks I gonna use this approach now and do my tests. I need propagate my language because of another services needs return correct message by language code.

Leave a Reply

Your email address will not be published. Required fields are marked *