9

I would like to forward a request header with a feign client RequestInterceptor but, within RequestInterceptor.apply, RequestContextHolder.getRequestAttributes() is null, so is SecurityContextHolder.getContext().getAuthentication() (where I could also eventually get the value of my header).

This used to work before upgrading to Spring-Cloud Brixton, where the hystrix commands must now probably be run in a separate thread, because changing to the following parameter solves the problem :

hystrix.command.default.execution.isolation.strategy: SEMAPHORE

Now, I'm not too keen on changing this kind of default values if not necessary, is there another, recommended, way of forwarding headers now ?

Thanks

6
  • You can pass @RequestHeader to a feign method. You could also individually set each feign call to SEMAPHORE with hystrix.command.<methodname>.execution.isolation.strategy: SEMAPHORE. Dec 3, 2015 at 23:39
  • @spencergibb : Thanks, that's what I thought. I'll annotate the doc of my project. Dec 4, 2015 at 7:31
  • I think we want to make thread vs semaphore isolation configurable in an easy manner. Dec 4, 2015 at 16:05
  • @spencergibb : this could help ... but as per the netflix doc it is recommended to with the THREAD isolation strategy (github.com/Netflix/Hystrix/wiki/…). In my case I think changing the isolation level to make the developement experience easier is not a good idea ... we will go with the @RequestHeader solution. Thanks a bunch anyways for the great work with spring cloud :-) Dec 4, 2015 at 16:35
  • @SébastienNussbaumer do you have an example. I don't quite understand how you'd get access to the RequestHeader in the Interceptor, i.e. the apply method. I'm facing a similar problem where a thread local var is returning null due to the second thread.
    – imamc
    Apr 20, 2016 at 5:48

2 Answers 2

7

For Spring Boot 2+ / Spring Cloud Finchley +, if you just need the security context you can set the following property :

hystrix.shareSecurityContext=true

And the request interceptor should work.


For other uses cases or earlier versions (many thanks to Spring Cloud Sleuth for the inspiration) :

"All" you have to do is implement an HystrixConcurrencyStrategy that passes the information along each time there is a thread change. The class that does something very similar in Sleuth is here.

For my specific case I would :

  1. Wrap the Callable in wrapCallable with, for example, an CallableWithAuthentication class that would hold the current authentication when constructed
  2. The CallableWithAuthentication call method would first restore the previously saved Authentication, then call the original action, then clean up the current Authentication, et voilà.

Once your HystrixConcurrencyStrategy is up your request interceptor will work again, even with Thread isolation.

Note check the rest of the project there are lots of other interesting instrumenting stuff (for RxJava for example).

5
  • Glad that you like! Maybe you'll contribute some stuff to us then :D Jul 21, 2016 at 12:00
  • @MarcinGrzejszczak: Time is the issue here, but hey, why not :) Aug 1, 2016 at 7:42
  • This only works if you are calling feignclient from current thread. Or do you have configuration where you are calling feign client from another thread? I'm using custom threadpoolexecutor which is doing some validations and calling external services. But in this case request attributes are not propagated :(
    – bilak
    Sep 13, 2016 at 12:53
  • Sure @bilak, you have to do something similar with your ThreadPoolExecutor ... Check out spring cloud sleuth, there might be code to help you do that ... Sep 13, 2016 at 13:02
  • Thank you very much! Saved much time) Works on version cloud - Greenwich.RELEASE and boot - 2.1.5.RELEASE Apr 23, 2020 at 19:41
0

Just to elaborate on @sebastian 's answer

public class RequestContextHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
    return new RequestAttributeAwareCallable<>(callable, RequestContextHolder.getRequestAttributes());
}

static class RequestAttributeAwareCallable<T> implements Callable<T> {

    private final Callable<T> delegate;
    private final RequestAttributes requestAttributes;

    public RequestAttributeAwareCallable(Callable<T> callable, RequestAttributes requestAttributes) {
        this.delegate = callable;
        this.requestAttributes = requestAttributes;
    }

    @Override
    public T call() throws Exception {
        try {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            return delegate.call();
        } finally {
            RequestContextHolder.resetRequestAttributes();
        }
    }
}

}

then somewhere in configuration

@PostConstruct
public void init() {
    HystrixPlugins.getInstance().registerConcurrencyStrategy(new RequestContextHystrixConcurrencyStrategy());
}

Refer following post

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.