These are chat archives for spring-cloud/spring-cloud

15th
Aug 2016
Spencer Gibb
@spencergibb
Aug 15 2016 15:29
eureka.instance.initialStatus=OUT_OF_SERVICE
pradeepkusingh
@pradeepkusingh
Aug 15 2016 15:30
@spencergibb - How this property works ? eureka.instance.initialStatus=OUT_OF_SERVICE
Spencer Gibb
@spencergibb
Aug 15 2016 15:33
instead of sending UP to eureka, send OUT_OF_SERVICE which wouldn’t get propogated to eureka clients like ribbon. You’d currently need to write code to change the status.
Mike Liu
@mikexliu
Aug 15 2016 16:05
is there a dedicated Zuul channel or should I use this channel?
Spencer Gibb
@spencergibb
Aug 15 2016 16:05
if you’re using spring-cloud-netflix, then yes
Mike Liu
@mikexliu
Aug 15 2016 16:08
thanks! I was running through the tutorials/documentation. i set up a zuul proxy and am using eureka to discover the services. i can see the routes correctly but when i try to access the service endpoint (for example, if i have a service named app, i go to https://proxy:1234/app), it throws an error in the log complaining about a bad URI. inspecting it shows only the https field is created, no information about the host, port, or endpoint. I am wondering if theres a special case i'm missing since i'm using https?
Mike Liu
@mikexliu
Aug 15 2016 16:13
@dsyer I've read through that; here's eureka's output: https://gist.github.com/mikexliu/5677242a3d8ce005364a3cf5efeafc81 is there any field i'm missing that's immediately obvious?
Dave Syer
@dsyer
Aug 15 2016 16:15
It's a bit weird that the non secure port is the same as the secure port
But I don't see anything else obviously wrong
What do you mean by "go to https://proxy:1234/app"?
"proxy" is presumably resolvable to a physical host in your environement?
Mike Liu
@mikexliu
Aug 15 2016 16:16
i mean if i try to access my service via zuul. /app is pointing to where my service is at (route exists through discovery service)
yeah sorry
proxy is just like localhost
Dave Syer
@dsyer
Aug 15 2016 16:17
And the back end services are addressable over HTTPS?
Mike Liu
@mikexliu
Aug 15 2016 16:18
app: https://localhost:5555, zuul proxy: https://localhost:1234/app, then this should point to https://localhost:5555 i assume
yes
everything is accessible via https
Dave Syer
@dsyer
Aug 15 2016 16:18
With proper certificates?
Mike Liu
@mikexliu
Aug 15 2016 16:18
yep
well, i assume so. it is self signed and stored in the java key store
Dave Syer
@dsyer
Aug 15 2016 16:19
Maybe the stack trace has some more detail?
It's also not clear what you mean by "the https field".
Mike Liu
@mikexliu
Aug 15 2016 16:20
internally in zuul, it's building an URI object. only the scheme field is set. the others are all null
Dave Syer
@dsyer
Aug 15 2016 16:23
That's clearly an error. Don't know why it's doing that though.
Dave Syer
@dsyer
Aug 15 2016 16:29
Does it work with http?
Mike Liu
@mikexliu
Aug 15 2016 16:37
let me give iet a try
Mike Liu
@mikexliu
Aug 15 2016 16:53
@dsyer seems to work on http..
Spencer Gibb
@spencergibb
Aug 15 2016 17:05
@mikexliu that’s odd
Mike Liu
@mikexliu
Aug 15 2016 17:10
@spencergibb yeah, i'm not sure what else i could try.. :\
Mike Liu
@mikexliu
Aug 15 2016 17:27

ahh, i think i see the issue. In RibbonClientConfiguration.java

if (!"https".equals(scheme) && this.serverIntrospector.isSecure(server)) {
                original = UriComponentsBuilder.fromUri(original).scheme("https").build()
                        .toUri();
            }

internally, it calls this part and builds the URI immediately before calling return super.reconstructURIWithServer(server, original);. But it's not a valid URI because original is blank. There's no request (the path is just ""). Using:

original = UriComponentsBuilder.fromUri(original).scheme("https").host(server.getHost()).port(server.getPort()).build()
                        .toUri();

Seemed to get me further. Now it seems like an ssl issue (ip vs localhost hostname verifier).
@spencergibb @dsyer

Spencer Gibb
@spencergibb
Aug 15 2016 17:28
PR?
Mike Liu
@mikexliu
Aug 15 2016 17:29
i can submit one after i fix my ssl issue (since it's unconfirmed this works end to end yet)
Spencer Gibb
@spencergibb
Aug 15 2016 17:29
sure
Mike Liu
@mikexliu
Aug 15 2016 17:31
@spencergibb do you know where i can look to override the HostnameVerifier for zuul?
(if you know by memory :P)
Spencer Gibb
@spencergibb
Aug 15 2016 17:32
I don’t know by memory
Mike Liu
@mikexliu
Aug 15 2016 18:01
@spencergibb all right, after setting the ribbon client to ignore hostname validation, seems to work. i'll submit a PR later today
bitsofinfo
@bitsofinfo
Aug 15 2016 19:38

I have a FeignClient defined like this:

@FeignClient(name="my-service", 
            decode404=true,
            fallback = MyFallback.class,
            configuration=MyConfig.class)
public interface MyClient {

    @RequestMapping(method=RequestMethod.GET, value = "/my/path/{x}", produces = "application/json")
    public ResponseEntity<? extends Object> getSomething(@PathVariable("x") String x);
}

MyConfig.class looks like this

@Configuration
public class MyConfig {

    @Bean 
    public Logger.Level loggerLevel() {
        return Logger.Level.BASIC;
    }

    @Bean
    public ErrorDecoder errorDecoder() {
        return new MyErrorDecoder();
    }

Neither of the @Bean annotated methods in MyConfig.class are being invoked. Thoughts on where I should begin looking for the issue?

Spencer Gibb
@spencergibb
Aug 15 2016 19:44
where do you define @FeignClients?
@bitsofinfo :arrow_up:
bitsofinfo
@bitsofinfo
Aug 15 2016 19:45
On another @Configuration annotated class that is brought in by a annotation on my main config class such as:
@Configuration
@EnableFeignClients(clients={MyClient.class})
public class MyConfiguration2 {
...
}
Note that if I reference MyConfig.class in the defaultConfiguration of the latter code, then it DOES get invoked. But not when referenced on the client interface itself
Spencer Gibb
@spencergibb
Aug 15 2016 19:47
don’t know. I was guessing a class scanning issue, but you’re using clients.
bitsofinfo
@bitsofinfo
Aug 15 2016 19:47
i.e. this works
@EnableFeignClients(clients={MyClient.class}, 
                    defaultConfiguration=MyConfig.class)
Dave Syer
@dsyer
Aug 15 2016 19:51
MyConfig should only be instantiated when the client is used (if not the default).
bitsofinfo
@bitsofinfo
Aug 15 2016 19:51
With the latter the @Bean for my ErrorDecoder is constructed when the FeignClient is created. (And every other feignClient)
Dave Syer
@dsyer
Aug 15 2016 19:51
Did you actually call any methods in MyClient?
bitsofinfo
@bitsofinfo
Aug 15 2016 19:51
yeah MyConfig is not being called at all (yes they are called). When specified on configuration of the @FeignClient itself
Dave Syer
@dsyer
Aug 15 2016 19:52
Sounds like a bug. But we do test that scenario.
bitsofinfo
@bitsofinfo
Aug 15 2016 19:56
funny, its invoked on every client other than the one I need it for
David Welch
@dwelch2344
Aug 15 2016 20:09
@spencergibb just saw your reply about out-of-service. we've been thinking that's the route we'll go, so glad we're not off our rockers on it
thanks
bitsofinfo
@bitsofinfo
Aug 15 2016 20:23
So with my custom ErrorDecoder @Bean declared, why would feign.SynchronousMethodHandler's constructor only ever get an instance of org.springframework.cloud.sleuth.instrument.web.client.feign.TraceFeignErrorDecoder can one not have a custom ErrorDecoder if slueth is in use?
Spencer Gibb
@spencergibb
Aug 15 2016 20:24
it should work
Dave Syer
@dsyer
Aug 15 2016 20:25
Sleuth and Feign was not a match made in heaven though
So I'd be prepared to believe it doesn't
Marcin is planning to re-write bits of feign to make it more instrumentable
bitsofinfo
@bitsofinfo
Aug 15 2016 20:29
hmm, yeah feign.hystrix.HystrixFeign.Builder.build() has its errorDecoder set = TraceFeignErrorDecoder
Spencer Gibb
@spencergibb
Aug 15 2016 20:30
IIRC, that is one of the bits to go away
bitsofinfo
@bitsofinfo
Aug 15 2016 20:30
SleuthHystrixFeignBuilder
This message was deleted
static Feign.Builder builder(BeanFactory beanFactory) {
        return HystrixFeign.builder()
                .client(new TraceFeignClient(beanFactory))
                .retryer(new TraceFeignRetryer(beanFactory))
                .decoder(new TraceFeignDecoder(beanFactory))
                .errorDecoder(new TraceFeignErrorDecoder(beanFactory));
    }
looks like this is hardcoded
so... hmm. Well I'm just trying to make this work for my need. Perhaps a workaround is to provide a new @Primary bean of this type?
    @Bean
    @Scope("prototype")
    @ConditionalOnClass(HystrixCommand.class)
    @ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = true)
    Feign.Builder feignHystrixBuilder(BeanFactory beanFactory) {
        return SleuthHystrixFeignBuilder.builder(beanFactory);
    }
then extend mine from TraceFeignErrorDecoder
bah... its final. :(
hardwired to delegate to new ErrorDecoder.Default();
maybe my own in same package but replicate it and extend from FeignEventPublisher
bitsofinfo
@bitsofinfo
Aug 15 2016 22:35

If I have an ErrorDecoder that traps a 404, and throws my own "application specific exception", how can I get this to bubble up to the code that is invoking my feign client? It seems that regardless of if I have a custom ErrorDecoder or not, since everything is wrapped in Hystrix, that that will always trip my fallback class. The only way not trip trip the hystrix fallback is to return a 200 or 404 (with decode404=true) with a body that is converable to the declared return type on my feign interface; correct?

So is the only solution in this case to have my REST endpoint, return only 200's (or 404's with decode404=true), and return such JSON that is unmarshallable into something super basic, like a map? I.e. a return structure that serves for both legit responses and those representing errors, (rather than relying on HTTP response codes?)

I'm just trying to nail down the best way of implementing this I guess. Ideally I would like the hystrix fallbacks to only be invoked on 500 http responses or literal failure to connect to the endpoints. Anything other than that I'd like to translate into an appropriate app specific exception that is bubbled back to the feign client calling code, as handled by a feign ErrorDecoder and as described in it's Javadocs.