Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Communication between two microservices #3649

Closed
MBenali opened this issue May 26, 2016 · 42 comments
Closed

Communication between two microservices #3649

MBenali opened this issue May 26, 2016 · 42 comments

Comments

@MBenali
Copy link

MBenali commented May 26, 2016

How to make Comunication between two microservices (microservices are generated with JWT security)

Hi,
In the first, I note that hhis is not a bug, but I did not know where to make my request

Used JHipster (v3.1.0) to generate 2 microservices (2 gateway and 2 microservices, with JWT security):

1st composant) Reference component "ref_gw" gateway app and "ref_ms" : microservice

2nd composant) "Reception_gw" : gateway app, and "reception_ms" microservice

Our need: the microservice "reception_ms" has to verify certain data which are quoted ref_ms, (by REST GET or POST Method)

I saw some documentations (theory only) speaking of discovery server-side (or the passage by the registery, other on spring cloud and AMQP,...), but how to implement it (registery solution) I found nothing.

Thank you

@deepu105
Copy link
Member

@xetys wrote an article which had a section dealing with this check this http://stytex.de/blog/2016/03/25/jhipster3-microservice-tutorial/

@deepu105
Copy link
Member

ping @sdoxsee @PierreBesson

@MBenali
Copy link
Author

MBenali commented May 26, 2016

Thanks @deepu105
I hope that that is going to work.
I'll test and I inform you

@cbornet
Copy link
Member

cbornet commented May 26, 2016

Note that there is a module that can help you generate your clients. It's not based on RestTemplate but on Netflix's Feign so it should be easy to plug Ribbon/Eureka.

@MBenali
Copy link
Author

MBenali commented May 26, 2016

Thanks @cbornet

@jdubois
Copy link
Member

jdubois commented May 26, 2016

Great article @xetys ! Ping me on Twitter next time, so I know and can RT you!

@PierreBesson
Copy link
Contributor

Hi @MBenali, maybe you can take a look of what I did here: https://github.com/PierreBesson/jhipster-circuit-breaker-demo using Feign as a Rest client for microservices.
Also have a look at this article about Feign and Spring Cloud: https://dzone.com/articles/the-netflix-stack-using-spring-boot-part-3-feign

@MBenali
Copy link
Author

MBenali commented May 26, 2016

Thanks to all

MBenali

@cbornet
Copy link
Member

cbornet commented May 26, 2016

I didn't code yet the swagger template for microservice using @FeignClient but I think the current swagger-cli module should work well with spring cloud's autoconfiguration of Ribbon.
For an eureka service named "foo", something like

    @Bean
    public FeignApiClient FooRibbonApiClient() {
        FeignApiClient apiClient = createApiClient(FooApiClientProperties, feignEncoder, feignDecoder);
        apiClient.getFeignBuilder().client(feign.ribbon.RibbonClient.create()); // or better: create a RibbonClient bean
        apiClient.setBasePath("http://foo");
        return apiClient;
    }

@xetys
Copy link
Member

xetys commented May 27, 2016

i am currently stuck in upcomming-deadline-phases.....I have the following in mind...

  • PR to docs of how to use OAuth2 and the new JHipster UAA
  • PR to JHipster for a proper entityservice generator

i was trying Netflix Feign yesterday but i was really stuck on configuring the oauth2 behaviour.
There is an OAuth2RestTemplate, which is not that declarative as Feign is, but it actually has OAuth2 handling.

Since I am not familar with feign so far, I would appreciate some help from anyone who knows it in detail.

Otherwise I could share my dirtyhacking workaround to passs access tokens to feign...

or simply use OAuth2RestTemplate

@cbornet
Copy link
Member

cbornet commented May 27, 2016

@xetys You can see here how it is done in swagger-codegen.

@xetys
Copy link
Member

xetys commented May 27, 2016

thanks @cbornet, I will try that out

@PierreBesson
Copy link
Contributor

@xetys, I think Feign integration with OAuth2 is already merged here: spring-attic/spring-cloud-security@2718a04

I was thinking that we should a similar Feign Request Interceptor for JWT.

@xetys
Copy link
Member

xetys commented May 28, 2016

@PierreBesson, i am thinking of finding an hour, maybe together with @cbornet, to wire things in a right way. i believe this would be quite fast, because it would take me some more time to figure out the best practice (I started using spring just some months ago 😆)

@xetys
Copy link
Member

xetys commented May 29, 2016

ok, couldn't hold myself and figured out....thanks to @PierreBesson hinting me there is already a spring side interceptor....so all you need is actually define a OAuth2ProtectedResourceDetails an declare the interceptor bean like this:

@Bean
    public RequestInterceptor getOAuth2RequestInterceptor() throws IOException {
        log.info("installing OAuth2 request interceptor to feign");
        return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), geOAuth2ProtectedResourceDetails());
    }

and that's it!

I PR all what is needed the next days...

xetys added a commit to xetys/generator-jhipster that referenced this issue May 29, 2016
so feign clients can be added declarative to. This is a requirement for the next step of
a JHipster feign client subgenerator.

for feature request jhipster#3649
@MBenali
Copy link
Author

MBenali commented May 30, 2016

Hi @xetys
I tried to follow your article "http://stytex.de/blog/2016/03/25/jhipster3-microservice-tutorial/ " (I have to have forgotten some things ...),

I want to find an information for the microservice reception_ms by REST calling the microservice reference_ms

The modifications in my code:

in microservice : reception_ms i add the classes :

  • AbstractMicroserviceClient
  • ReferentielClient who extends AbstractMicroserviceClient and i give the name of the microservice to the constructor like this: [public ReferentielClient() {super("referentiel_ms");}]
  • RestTemplateConfiguration
  • Referentiel (POJO)
    in this micro service, i test a rest call (Collection findAll = client.findAll();)

in the Referentiel_Gateway, i add @EnableCircuitBreaker to the ReferentielGwApp (I have to make the same thing on the second Gateway: Reception_GW ? )

in the microservice : Referentiel_ms, i modify MicroserviceSecurityConfiguration (.antMatchers("/api/**") //FOR TESTING!, ... )

here is the exception which I obtained

2016-05-30 18:56:46.740  WARN 10735 --- [nio-9081-exec-5] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ribbonLoadBalancerContext' defined in org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration: Unsatisfied dependency expressed through constructor argument with index 0 of type [com.netflix.loadbalancer.ILoadBalancer]: Error creating bean with name 'ribbonLoadBalancer' defined in org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.netflix.loadbalancer.ILoadBalancer]: Factory method 'ribbonLoadBalancer' threw exception; nested exception is java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@2fb93200 rejected from java.util.concurrent.ScheduledThreadPoolExecutor@17159506[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 8]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ribbonLoadBalancer' defined in org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.netflix.loadbalancer.ILoadBalancer]: Factory method 'ribbonLoadBalancer' threw exception; nested exception is java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@2fb93200 rejected from java.util.concurrent.ScheduledThreadPoolExecutor@17159506[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 8]





org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ribbonLoadBalancerContext' defined in org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration: Unsatisfied dependency expressed through constructor argument with index 0 of type [com.netflix.loadbalancer.ILoadBalancer]: Error creating bean with name 'ribbonLoadBalancer' defined in org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.netflix.loadbalancer.ILoadBalancer]: Factory method 'ribbonLoadBalancer' threw exception; nested exception is java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@763bd34 rejected from java.util.concurrent.ScheduledThreadPoolExecutor@17159506[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 8]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ribbonLoadBalancer' defined in org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.netflix.loadbalancer.ILoadBalancer]: Factory method 'ribbonLoadBalancer' threw exception; nested exception is java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@763bd34 rejected from java.util.concurrent.ScheduledThreadPoolExecutor@17159506[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 8]
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:464)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.cloud.context.named.NamedContextFactory.createContext(NamedContextFactory.java:109)
    at org.springframework.cloud.context.named.NamedContextFactory.getContext(NamedContextFactory.java:75)
    at org.springframework.cloud.context.named.NamedContextFactory.getInstance(NamedContextFactory.java:114)
    at org.springframework.cloud.netflix.ribbon.SpringClientFactory.getInstance(SpringClientFactory.java:103)
    at org.springframework.cloud.netflix.ribbon.SpringClientFactory.getLoadBalancer(SpringClientFactory.java:55)
    at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.getLoadBalancer(RibbonLoadBalancerClient.java:126)
    at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.getServer(RibbonLoadBalancerClient.java:115)
    at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose(RibbonLoadBalancerClient.java:65)
    at com.any.appli.applii.ms.client.AbstractMicroserviceClient.getUrl(AbstractMicroserviceClient.java:68)
    at com.any.appli.applii.ms.client.ReferentielClient.findAll(ReferentielClient.java:56)

@xetys
Copy link
Member

xetys commented May 30, 2016

@MBenali is "referentiel_ms" the name appearing in eureka?

@MBenali
Copy link
Author

MBenali commented May 30, 2016

@xetys yes referentiel_ms is the name appearing in eureka,

i add the @EnableCircuitBreaker to the second Gateway (ReceptionGwApp) , and now i retrieve (discover) my microsservice, but i obtain this exception:

2016-05-30 20:19:33.353 DEBUG 12056 --- [nio-9081-exec-1] s.n.www.protocol.http.HttpURLConnection  : sun.net.www.MessageHeader@1e41ce56 pairs: {null: HTTP/1.1 404 Not Found}{Server: Apache-Coyote/1.1}{X-Application-Context: referentiel_ms:dev:8081}{Content-Type: application/json;charset=UTF-8}{Transfer-Encoding: chunked}{Date: Mon, 30 May 2016 18:19:33 GMT}
org.springframework.web.client.HttpClientErrorException: 2016-05-30 20:19:33.353 DEBUG 12056 --- [nio-9081-exec-1] s.n.www.protocol.http.HttpURLConnection  : 
sun.net.www.MessageHeader@1e41ce56 pairs: {null: HTTP/1.1 404 Not Found}{Server: Apache-Coyote/1.1}{X-Application-Context: referentiel_ms:dev:8081}{Content-Type: application/json;charset=UTF-8}{Transfer-Encoding: chunked}{Date: Mon, 30 May 2016 18:19:33 GMT}
org.springframework.web.client.**HttpClientErrorException: 404 Not Found**
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:641)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557)
    at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:289)
    at com.rte.appli.applii.ms.client.ReferentielClient.findAll(ReferentielClient.java:56)

@xetys
Copy link
Member

xetys commented May 31, 2016

@MBenali this is the time where 404 means something good...it least you are connected to your service and the url is not correct. Maybe we proceed this talk in a chat like gitter? I am afraid of spamming this issue forum a bit 😄

@MBenali
Copy link
Author

MBenali commented May 31, 2016

Ok, @xetys
we can exchange about this subject on gitter

@pascalgrimaud pascalgrimaud changed the title Comunication between two microservices Communication between two microservices May 31, 2016
@cbornet
Copy link
Member

cbornet commented Jun 3, 2016

@xetys @PierreBesson I added an option in swagger-codegen to generate a stub interface like what is described here. Would you help me test it before I PR ?
You can use the generated petstore sample or generate for your own swagger spec with java -jar swagger-codegen.jar generate -i swagger.json -l springboot -DinterfaceOnly=true (after packaging swagger-codegen from my branch)
After that, all is needed is to configure your clients the way you want (w/wo Eureka, w/wo Hystrix, ...) with @FeignClient annotations. Eg:

@FeignClient(name="pet", url="http://petstore.swagger.io/v2")
public interface PetClient extends PetApi {

}

@PierreBesson
Copy link
Contributor

@cbornet, It's a very interesting solution.

I did some testing with your branch but only on the petstore. I will try to use it on my Feign Circuit Breaker demo to see if it works in this case.
I noticed that some tests didn't pass when building swagger-codegen.jar but maybe it's not your fault...

Do you know if Hystrix fallbacks will be available even if not using Ribbon/Eureka ?

@cbornet
Copy link
Member

cbornet commented Jun 3, 2016

Yes it's my fault 😄 . I have fixed the tests now.

From what I understand Ribbon is always used with FeignClient (with or without Eureka).
Hystrix doesn't seem to have any relationship with Ribbon so I think you can use it without Eureka.

@cbornet
Copy link
Member

cbornet commented Jun 3, 2016

Just had it working on a monolith app. This is just awesome ! I'll upgrade my module asap as it's much more integrated and flexible than what I had done !

@cbornet
Copy link
Member

cbornet commented Jun 3, 2016

There is an issue with petstore endpoints that have multiple "produces" (spring-cloud/spring-cloud-netflix#808). I'll see how this can be dealt.

@cbornet
Copy link
Member

cbornet commented Jun 6, 2016

@PierreBesson I confirm it works with Hystrix without Eureka. Hystrix is even enabled by default on my monolithic test app.

@PierreBesson
Copy link
Contributor

@cbornet I just did some more tests today with your branch codegen.jar and JHipster Microservices and its really promising as we only have to generate the @FeignClient class.
So in your module we should switch to using Spring Cloud Feign even for the monolith.
Once you have updated your module, I can help you add some options for microservices (requesting Eureka, etc...).

@PierreBesson
Copy link
Contributor

That's a really good news. Did you try to do a fallback using Hystrix using :
@FeignClient(name = "app", fallback = ClientFallback.class)

@cbornet
Copy link
Member

cbornet commented Jun 6, 2016

Arf ! I have this issue : spring-cloud/spring-cloud-netflix#1023
Since there is a @RequestMapping generated on the interface, spring-MVC interprets it as a controller !!
So I get a first controller for the FeignClient interface and then another one for the Hystrix fallback class and it fails during startup...
I need to see how to remove this @RequestMapping from the generated interface.

@xetys
Copy link
Member

xetys commented Jun 6, 2016

mhm....i hadn't any problems in my setup where the feign client are also using @RequestMapping as well....

@PierreBesson
Copy link
Contributor

@cbornet I had noticed that the interface show up as a controller in the Swagger UI but same as @xetys, I didn't have problems before...

@cbornet
Copy link
Member

cbornet commented Jun 6, 2016

Does it still work when you add the Hystrix fallback ?

@cbornet
Copy link
Member

cbornet commented Jun 6, 2016

See spring-cloud/spring-cloud-netflix#466 (more explicit)

@PierreBesson
Copy link
Contributor

@cbornet, I confirm that it doesn't work with an interface generated by your swagger-codegen. As soon as I add the fallback it fails to launch.
As far as I understand, this is caused by having an @RequestMapping both on the interface and on the method. When I removed the one on the interface the app could start fine. But then we need to change the rest of the generated "interface client".

@cbornet
Copy link
Member

cbornet commented Jun 6, 2016

I fixed it (removed the RequestMapping on the interface and adjusted the path in the methods). Can you check ?

@cbornet
Copy link
Member

cbornet commented Jun 6, 2016

@PierreBesson
Copy link
Contributor

@cbornet, the spring-cloud/spring-cloud-netflix#1023 issue is now fixed and released in Brixton SR1. I have made PR to upgrade. Please tell us if it helps with your problem.

@cbornet
Copy link
Member

cbornet commented Jun 15, 2016

I don't think it really fixes the issue. The problem is in spring-framework so I don't think it can be solved.

@cbornet
Copy link
Member

cbornet commented Jul 8, 2016

@PierreBesson @xetys I have updated the swagger-cli module to use the spring-cloud-feign codegen. Would you make some tests before I publish to npm ?

@russTbaker
Copy link

I've used the org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor in the past and it has worked well for me. However, in my current project I'm not using OAuth2, just JWT. What would be nice would be to have the ability to use either and have JHipster generate the necessary classes and configuration to do that.

Any feelings about that?

Thanks,

Russ Baker

@xetys
Copy link
Member

xetys commented Jul 23, 2016

@cbornet yes, i got a pretty stack of things to do on this and on that but due to a tight schedule I just had not the time....I issued to return to our feign problems during the next week

@russTbaker For me its some conceptional problem, because there is no support of a pure maschine recognition for internal calls using that mechanism. The only thing you can do here is to pass the jwt from request if possible, so internal requests are threated as similar to your gateway requests.

This at least is limiting the security options with pure jwt, as well as centralizing to much responsibility on the gateway...as I see it...

if you still want to go this way, @PierreBesson already started an approach of using a JwtRequestInterceptor. I take a look as soon I solve my issues on that topic

@jdubois
Copy link
Member

jdubois commented Sep 16, 2016

Closing as I think the question is answered...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants