0

I am trying to understand how to host a Spring Boot Gemfire server process.

I found this example Spring Gemfire Server

The problem I am having is the the server I am trying to add to the cluster is not showing up in the cluster after I start the process.

Here are the steps I am taking:

  1. Start a new locator locally (default port): gfsh>start locator --name=loc-one

  2. I want to add this SpringBootGemfireServer to the cluster:

note I have commented out the embeded locator start-up - I want to add this to the existing locator already running

    @SpringBootApplication
    @SuppressWarnings("unused")
    public class SpringGemFireServerApplication {

        private static final boolean DEFAULT_AUTO_STARTUP = true;

        public static void main(String[] args) {
           SpringApplication.run(SpringGemFireServerApplication.class, args);
    }

    @Bean
    static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
        return new PropertyPlaceholderConfigurer();
    }

    private String applicationName() {
    return SpringGemFireServerApplication.class.getSimpleName();
    }

    @Bean
    Properties gemfireProperties(
          @Value("${gemfire.log.level:config}") String logLevel,
          @Value("${gemfire.locator.host-port:localhost[10334]}") String locatorHostPort,
          @Value("${gemfire.manager.port:1099}") String managerPort) {

    Properties gemfireProperties = new Properties();

    gemfireProperties.setProperty("name", applicationName());
    gemfireProperties.setProperty("log-level", logLevel);
    //gemfireProperties.setProperty("start-locator", locatorHostPort);
    //gemfireProperties.setProperty("jmx-manager", "true");
    //gemfireProperties.setProperty("jmx-manager-port", managerPort);
    //gemfireProperties.setProperty("jmx-manager-start", "true");

    return gemfireProperties;
    }

    @Bean
    CacheFactoryBean gemfireCache(@Qualifier("gemfireProperties") Properties gemfireProperties) {

    CacheFactoryBean gemfireCache = new CacheFactoryBean();

    gemfireCache.setClose(true);
    gemfireCache.setProperties(gemfireProperties);

    return gemfireCache;
}

@Bean
CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache,
        @Value("${gemfire.cache.server.bind-address:localhost}") String bindAddress,
        @Value("${gemfire.cache.server.hostname-for-clients:localhost}") String hostNameForClients,
        @Value("${gemfire.cache.server.port:40404}") int port) {

    CacheServerFactoryBean gemfireCacheServer = new CacheServerFactoryBean();


    gemfireCacheServer.setCache(gemfireCache);
    gemfireCacheServer.setAutoStartup(DEFAULT_AUTO_STARTUP);
    gemfireCacheServer.setBindAddress(bindAddress);
    gemfireCacheServer.setHostNameForClients(hostNameForClients);
    gemfireCacheServer.setPort(port);

    return gemfireCacheServer;
}

@Bean
PartitionedRegionFactoryBean<Long, Long> factorialsRegion(Cache gemfireCache,
        @Qualifier("factorialsRegionAttributes") RegionAttributes<Long, Long> factorialsRegionAttributes) {

    PartitionedRegionFactoryBean<Long, Long> factorialsRegion = new PartitionedRegionFactoryBean<>();

    factorialsRegion.setAttributes(factorialsRegionAttributes);
    factorialsRegion.setCache(gemfireCache);
    factorialsRegion.setClose(false);
    factorialsRegion.setName("Factorials");
    factorialsRegion.setPersistent(false);

    return factorialsRegion;
}

@Bean
@SuppressWarnings("unchecked")
RegionAttributesFactoryBean factorialsRegionAttributes() {

    RegionAttributesFactoryBean factorialsRegionAttributes = new RegionAttributesFactoryBean();

    factorialsRegionAttributes.setCacheLoader(factorialsCacheLoader());
    factorialsRegionAttributes.setKeyConstraint(Long.class);
    factorialsRegionAttributes.setValueConstraint(Long.class);

    return factorialsRegionAttributes;
}

FactorialsCacheLoader factorialsCacheLoader() {
    return new FactorialsCacheLoader();
}

class FactorialsCacheLoader implements CacheLoader<Long, Long> {

    // stupid, naive implementation of Factorial!
@Override
    public Long load(LoaderHelper<Long, Long> loaderHelper) throws CacheLoaderException {

        long number = loaderHelper.getKey();

        assert number >= 0 : String.format("Number [%d] must be greater than equal to 0", number);

        if (number <= 2L) {
            return (number < 2L ? 1L : 2L);
        }

        long result = number;

        while (number-- > 1L) {
            result *= number;
        }

        return result;
    }

    @Override
    public void close() {
    }
}

}

When I go to gfsh>connect list members

I only see the locator.

JDBennett
  • 1,323
  • 17
  • 45

1 Answers1

2

I haven't verified the full configuration to check whether there's something else wrong, but the main issue I see right now is that you seem to be confusing the start-locator property (automatically starts a locator in the current process when the member connects to the distributed system and stops the locator when the member disconnects) with the locators property (the list of locators used by system members, it must be configured consistently for every member of the distributed system). Since you're not correctly setting the locators property when configuring the server, it just can't join the existing distributed system because it doesn't know which locator to connect to.

The default locator port used by GemFire is 10334, so you should change your gemfireProperties method as follows:

@Bean
Properties gemfireProperties(@Value("${gemfire.log.level:config}") String logLevel, @Value("${gemfire.locator.host-port:localhost[10334]}") String locatorHostPort, @Value("${gemfire.manager.port:1099}") String managerPort) {
  Properties gemfireProperties = new Properties();
  gemfireProperties.setProperty("name", applicationName());
  gemfireProperties.setProperty("log-level", logLevel);
  // You can directly use the locatorHostPort variable instead.
  gemfireProperties.setProperty("locators", "localhost[10334]");

  return gemfireProperties;
}

Hope this helps.

Cheers.

Juan Ramos
  • 1,421
  • 1
  • 8
  • 13
  • Perfect. I think I understood the start-locator process (as in it would start a new locator within the same process) - that is why I commented it out. Since I started the locator locally (outside of the java process) and it was running on 10334 - I just assumed that the server instance would find that locator running and join that cluster. I did not realize I still had to explicitly set the locator property. – JDBennett Aug 08 '18 at 13:29
  • Yes, you always have to configure the full list of locators used within the cluster in every single member. – Juan Ramos Aug 08 '18 at 14:31
  • Urizen is correct. This is primarily because the Locator list determines the distributed system/cluster to which the new peer member will join, & therefore must be explicitly declared/set. Previously, GemFire/Geode used mcast networking to form a cluster, but the problem with mcast is that you can end up with unexpected members in the cluster too. So, it is better to be explicit. A recent SO post goes into more details about the `locators` and `start-locator` properties... https://stackoverflow.com/questions/51659771/start-locator-locators-which-is-for-client-and-which-is-for-server – John Blum Aug 08 '18 at 19:07
  • Also note, the example you cited above (https://github.com/jxblum/spring-boot-gemfire-server-example) is a fairly old example now. My new direction is to showcase the new Annotation-based configuration model (https://docs.spring.io/spring-data/gemfire/docs/current/reference/html/#bootstrap-annotation-config) introduced in SDG 2.0. – John Blum Aug 08 '18 at 19:12
  • Here is an example server that starts a CacheServer with an embedded Locator/Manager when the `locator-manager` Spring profile is enabled (https://github.com/jxblum/contacts-application/blob/master/boot-example/src/main/java/example/app/geode/cache/server/GeodeServerApplication.java). – John Blum Aug 08 '18 at 19:12
  • If you do not enable the `locator-manager` profile and rather start a Locator using Gfsh on `localhost` using the default Locator port (`10334`), then you can connect this server up to the Locator given the `@CacheServerApplication` annotation `locators` property is set to "`localhost[10334]`". Either way, it works. If you do not start a Locator using Gfsh, you can enable the `locator-manager` Spring profile and connect to this Spring Boot configured/bootstrapped server using `gfsh>connect`. – John Blum Aug 08 '18 at 19:14