Wait until ApplicationReadyEvent to register
Use Zuul with ZookeeperDiscovery, and Zuul return 404 when deploying services. The reason seems that ZookeeperDiscovery register service in start of LifeCycle. In that time, the container has no beed fully started so that any request returns 404.
Is there any work around to delay registration of ZookeeperDiscovery?
Thanks
There will be a delay between when services are registered in zookeeper and when they are available in zuul. Unsure how delaying registration of ZookeeperDiscovery would help.
Is there any way to delay registration until health check return up? Like what Eureka did.
I'm still not sure what you are asking for. What did Eureka do?
The thing is that, after it was registered on zookeeper, the service may take some time to finish its initialization to serve incoming requests. During this period, other services may discover it and send request to it and then get a 404 error.
It would be great if the registration could be the last step of starting up, which is, after the service is ready.
PS: This 404 error was not observed when using Eureka.
Eureka doesn't do anything specific to avoid this, it just takes up to 90 seconds to show up because of the various cache/wait times.
it shows up early than expectation. Zuul pick the service before it's fully started. So requests sent to this service get 404 error.
No need to repeat the problem. How would you know the service is "fully started"?
May we use ApplicationStartedEvent in Spring boot to detect "fully started"?
Registration already happens with the spring boot lifecycle. ApplicationStartedEvent seems too early to me according to the docs. ApplicationReadyEvent seems like a better candidate.
agree. ApplicationReadyEvent is better.
A temporary patch that verifies ApplicationReadyEvent is good moment to register service.
@Configuration
@ConditionalOnProperty(value = "spring.cloud.zookeeper.discovery.enabled", matchIfMissing = true)
@AutoConfigureBefore(ZookeeperDiscoveryClientConfiguration.class)
public class ZookeeperConfig {
@Autowired
private CuratorFramework curator;
@Bean
public ZookeeperServiceDiscovery zookeeperServiceDiscovery(ZookeeperDiscoveryProperties zookeeperDiscoveryProperties,
InstanceSerializer<ZookeeperInstance> instanceSerializer) {
return new DeferZookeeperServiceDiscovery(this.curator, zookeeperDiscoveryProperties, instanceSerializer);
}
public static class DeferZookeeperServiceDiscovery extends ZookeeperServiceDiscovery {
public DeferZookeeperServiceDiscovery(CuratorFramework curator, ZookeeperDiscoveryProperties properties,
InstanceSerializer<ZookeeperInstance> instanceSerializer) {
super(curator, properties, instanceSerializer);
}
@Override
public ServiceDiscovery<ZookeeperInstance> getServiceDiscovery() {
return new NoOpServiceDiscovery<>();
}
@EventListener
@SneakyThrows
public void handleContextRefresh(ApplicationReadyEvent event) {
super.getServiceDiscovery().start();
}
private static class NoOpServiceDiscovery<T> implements ServiceDiscovery<T> {
@Override
public void start()
throws Exception {
}
@Override
public void registerService(ServiceInstance<T> service)
throws Exception {
}
@Override
public void updateService(ServiceInstance<T> service)
throws Exception {
}
@Override
public void unregisterService(ServiceInstance<T> service)
throws Exception {
}
@Override
public ServiceCacheBuilder<T> serviceCacheBuilder() {
return null;
}
@Override
public Collection<String> queryForNames()
throws Exception {
return null;
}
@Override
public Collection<ServiceInstance<T>> queryForInstances(String name)
throws Exception {
return null;
}
@Override
public ServiceInstance<T> queryForInstance(String name, String id)
throws Exception {
return null;
}
@Override
public ServiceProviderBuilder<T> serviceProviderBuilder() {
return null;
}
@Override
public void close()
throws IOException {
}
}
}
}
It seems deregister services a little bit later so it also causes 404 error in a very short duration. But I could not find better ApplicationEvent to know when Spring is starting to shutdown.
This might be difficult because of the multiple application contexts (ie bootstrap) that are part of a spring cloud application.
+1 (delay discovery registration until ApplicationReadyEvent is fired)