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

Service not registering in Consul when packaged in war and deployed to external Tomcat #302

Open
whitneyh opened this issue Apr 19, 2017 · 18 comments

Comments

@whitneyh
Copy link

I have a Spring Cloud service that should register itself with Consul. When I start it with embedded Tomcat, this works as expected. However, when I package it as a war and deploy to an external Tomcat instance, it is not registering. There is no error or related messages in the console. It does not display the "Registering service with consul..." log message.

I have tried explicitly specifying server.port in bootstrap.yml but this does not change the behavior.

@spencergibb
Copy link
Member

From gitter he mentioned using boot 1.5.2 and Dalston.RELEASE.

See #173

@gaojia0814
Copy link

gaojia0814 commented May 2, 2017

@spencergibb ,
This problem has now been solved?
I use boot 1.5.2 and Dalston.RELEASE, this problem still exist

@spencergibb
Copy link
Member

No

@gaojia0814
Copy link

@spencergibb ,thanks!
the next version will solve?
or are there any other solutions ?

@spencergibb
Copy link
Member

No one is currently working on this.

@ask4gilles
Copy link

@whitneyh
I managed to register my external war with Consul with:

public class ExternalWarConsulRegistration implements ApplicationListener<ContextRefreshedEvent> {

  private final ConsulAutoRegistration registration;

  @Value("${server.port}")
  private Integer serverPort;

  public ExternalWarConsulRegistration(ConsulAutoRegistration registration) {
    this.registration = registration;
  }

  @Override
  public void onApplicationEvent(ContextRefreshedEvent event) {
    if (!isEmbeddedContext(event)) {
      registration.initializePort(serverPort);
    }
  }

  private boolean isEmbeddedContext(ContextRefreshedEvent event) {
    return event.getApplicationContext() instanceof EmbeddedWebApplicationContext &&
           ((EmbeddedWebApplicationContext) event.getApplicationContext()).getEmbeddedServletContainer() != null;
  }

@bdpeterson
Copy link

@ask4gilles
I seem to me missing something with your solution.
I receive:
No qualifying bean of type 'org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration'

Can you point me to what I am missing?

@vrnroman
Copy link

@ask4gilles @bdpeterson Did you implement any workarounds?

@bdpeterson
Copy link

@vrnroman I was able to generally solve it for my need.

I created a Configuration class that was ApplicationContextAware.

The basic code is below:

@Configuration
@ConditionalOnConsulEnabled
@ConditionalOnMissingBean(type= "org.springframework.cloud.consul.discovery.ConsulLifecycle")
@AutoConfigurationAfter(ConsulAutoServiceRegistrationAutoConfiguration.class)
public class MyConsulLifecycle implements ApplicationContextAware {

     @Autowired(required=false)
     private ConsulAutoServiceRegistration registration;

     @Autowired
     private Environment environment;

    public void setApplicationContext(ApplicationContext context) throws BeansException {
       if (registration !=null){
          String portNumber = environment.getProperty("server.port");
          registration.setPort(Integer.parseInt(portNumber));
          registration.start();
       }
    }
}

This assumes that you still set the server.port property (and this isn't normally used with deployed tomcat)

@bhagathk
Copy link

Hi all,

I am facing the same issue and I am able to register my service with the consul with the above code that @bdpeterson suggested. Thanks @bdpeterson.

I am able to see my service in the consul UI but the Application level health check is Failing. Can anyone give me an insight into why it's failing?

Also If I deploying the Application as a WAR on a Tomcat, should I have server.port property in the application.properties?

@bdpeterson
Copy link

@bhagathk Technically, no, you don't need the server.port property in the application.properties.
Those properties are used when you leverage the embedded server.

However, the code above requires server.port or some other property to set the registration port.

With your health check failing, confirm that you can connect to the health endpoint yourself. Often, it might be secured or otherwise rejecting connections.

Beyond that, more details would be needed to identify why it is failing.

@bhagathk
Copy link

Thanks for the quick response @bdpeterson. When I run the application using the embedded tomcat the application level health check is not failing, Only when I deploy the application as a War then the health check is failing?

@bdpeterson
Copy link

Check your application context. Deployed vs embedded default differently.
Use something like postman or curl to call the health endpoint.

@bhagathk
Copy link

I am seeing the below on the console application level health check.

"net/http: request canceled (Client.Timeout exceeded while awaiting headers)"

I myself not able to hit the health endpoint. I tried to hit the health endpoint from Postman and it says couldn't get any response?

@bhagathk
Copy link

I am able to get the application health check to work by changing the Default Health Url that Consul hits every 10 seconds to check the health of the service. I used sping.cloud.consul.discovery.healthCheckUrl to pass the Custom Health Url.

@M-BNCH
Copy link

M-BNCH commented Dec 13, 2018

@bdpeterson Thank you for your solution :)

How you define @AutoConfigurationAfter ?

@ceachother
Copy link

In Finchley.SR2 I have to use ConsulProperties to set the hostname and port

@jensdt
Copy link

jensdt commented Mar 5, 2019

FYI for other people looking at this for recent Spring Cloud versions, per @spencergibb at https://stackoverflow.com/a/54156442/9589945, setting server.port and then setting spring.cloud.consul.discovery.port=${server.port} should now be the way to go. I still needed the listener to actually start the registration because ConsulAutoServiceRegistrationListener is not triggered in WAR mode. Note that "@AutoConfigurationAfter" has been changed to "@AutoConfigureAfter"

So, properties:

server.port=your-port-here
spring.cloud.consul.discovery.port=${server.port}

Listener:

@Configuration
@ConditionalOnConsulEnabled
@ConditionalOnMissingBean(type= "org.springframework.cloud.consul.discovery.ConsulLifecycle")
@AutoConfigureAfter(ConsulAutoServiceRegistrationAutoConfiguration.class)
public class MyConsulListener implements ApplicationContextAware {

    @Autowired(required=false)
    private ConsulAutoServiceRegistration registration;

    public void setApplicationContext(ApplicationContext context) throws BeansException {
        if (registration != null){
            registration.start();
        }
    }
}

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