Repository: netflix/conductor
Issue: NullPointerException when starting up (using dynomite)

Using conductor version 2.1.0 (downloaded from https://bintray.com/netflixoss/maven/conductor/2.1.0)

Configuration is as follows (all IPs replaced with 1.2.3.4, they are unique in actual config)

I have validated the dynomite cluster is functioning properly using redis-cli

```
db=dynomite
workflow.dynomite.cluster=my-dyno
workflow.dynomite.cluster.name=my-dyno

workflow.dynomite.cluster.hosts=1.2.3.4:8102:us-west-2a:us-west-2;1.2.3.4:8102:us-west-2a:us-west-2;1.2.3.4:8102:us-east-1a:us-east-1;1.2.3.4:8102:us-east-1a:us-east-1;1.2.3.4:8102:eu-west-1a:eu-west-1;1.2.3.4:8102:eu-west-1a:eu-west-1

queues.dynomite.nonQuorum.port=8102
queues.dynomite.threads=10

workflow.namespace.prefix=my-conductor
wworkflow.namespace.queue.prefix=my-conductor-queue

# Elasticsearch

workflow.elasticsearch.instanceType=memory

# workflow.elasticsearch.url=my-elasticsearch.my.dom:9300
# workflow.elasticsearch.version=5
# workflow.elasticsearch.index.name=my-conductor-index


# I tried running with and without this property 
EC2_AVAILABILITY_ZONE=us-east-1a
```


Stack Trace
```
1) Error in custom provider, java.lang.RuntimeException: java.lang.NullPointerException
  while locating com.netflix.conductor.jedis.DynomiteJedisProvider
  at com.netflix.conductor.server.DynomiteClusterModule.configure(DynomiteClusterModule.java:25)
  while locating redis.clients.jedis.JedisCommands
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
        at com.netflix.dyno.jedis.DynoJedisClient$Builder.startConnectionPool(DynoJedisClient.java:4309)
        at com.netflix.dyno.jedis.DynoJedisClient$Builder.createConnectionPool(DynoJedisClient.java:4281)
        at com.netflix.dyno.jedis.DynoJedisClient$Builder.buildDynoJedisClient(DynoJedisClient.java:4257)
        at com.netflix.dyno.jedis.DynoJedisClient$Builder.build(DynoJedisClient.java:4186)
        at com.netflix.conductor.jedis.DynomiteJedisProvider.get(DynomiteJedisProvider.java:49)
        at com.netflix.conductor.jedis.DynomiteJedisProvider.get(DynomiteJedisProvider.java:14)
        at com.google.inject.internal.ProviderInternalFactory.provision(ProviderInternalFactory.java:81)
        at com.google.inject.internal.BoundProviderFactory.provision(BoundProviderFactory.java:72)
        at com.google.inject.internal.ProviderInternalFactory$1.call(ProviderInternalFactory.java:65)
        at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:115)
        at com.netflix.governator.event.ApplicationEventModule$ApplicationEventSubscribingProvisionListener.onProvision(ApplicationEventModule.java:89)
        at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:126)
        at com.google.inject.internal.ProvisionListenerStackCallback$Provision.provision(ProvisionListenerStackCallback.java:133)
        at com.google.inject.internal.ProvisionListenerStackCallback.provision(ProvisionListenerStackCallback.java:68)
        at com.google.inject.internal.ProviderInternalFactory.circularGet(ProviderInternalFactory.java:63)
        at com.google.inject.internal.BoundProviderFactory.get(BoundProviderFactory.java:62)
        at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
        at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092)
        at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
        at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:194)
        at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41)
        at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:205)
        at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:199)
        at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1085)
        at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(InternalInjectorCreator.java:199)
        at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:180)
        at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
        at com.google.inject.Guice.createInjector(Guice.java:99)
        at com.google.inject.Guice.createInjector(Guice.java:73)
        at com.netflix.conductor.bootstrap.Main.main(Main.java:53)
Caused by: java.lang.NullPointerException
        at com.netflix.dyno.connectionpool.impl.HostsUpdater.refreshHosts(HostsUpdater.java:111)
        at com.netflix.dyno.connectionpool.impl.ConnectionPoolImpl.start(ConnectionPoolImpl.java:486)
        at com.netflix.dyno.jedis.DynoJedisClient$Builder.startConnectionPool(DynoJedisClient.java:4292)
        ... 29 more
```

Full log (there are 51 "Error in custom provider" stack traces, mostly very similar)
[server.log](https://github.com/Netflix/conductor/files/2558912/server.log)




Changed files:
redis-persistence/src/main/java/com/netflix/conductor/jedis/TokenMapSupplierProvider.java

diff --git a/redis-persistence/src/main/java/com/netflix/conductor/jedis/TokenMapSupplierProvider.java b/redis-persistence/src/main/java/com/netflix/conductor/jedis/TokenMapSupplierProvider.java
index 627fed072..92a7ef207 100644
--- a/redis-persistence/src/main/java/com/netflix/conductor/jedis/TokenMapSupplierProvider.java
+++ b/redis-persistence/src/main/java/com/netflix/conductor/jedis/TokenMapSupplierProvider.java
@@ -1,43 +1,53 @@
+/*
+ * Copyright 2016 Netflix, Inc.
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
 package com.netflix.conductor.jedis;
 
-import com.google.common.collect.Lists;
-
 import com.netflix.dyno.connectionpool.Host;
-import com.netflix.dyno.connectionpool.HostSupplier;
 import com.netflix.dyno.connectionpool.TokenMapSupplier;
 import com.netflix.dyno.connectionpool.impl.lb.HostToken;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
+import com.netflix.dyno.connectionpool.impl.utils.CollectionUtils;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
 
 public class TokenMapSupplierProvider implements Provider<TokenMapSupplier> {
-    private final HostSupplier hostSupplier;
+    private final List<HostToken> hostTokens;
 
     @Inject
-    public TokenMapSupplierProvider(HostSupplier hostSupplier) {
-        this.hostSupplier = hostSupplier;
+    public TokenMapSupplierProvider() {
+        this.hostTokens = new ArrayList<>();
     }
 
     @Override
     public TokenMapSupplier get() {
         return new TokenMapSupplier() {
-
-            // FIXME This isn't particularly safe, but it is equivalent to the existing code.
-            // FIXME It seems like we should be supply tokens for more than one host?
-            HostToken token = new HostToken(1L, Lists.newArrayList(hostSupplier.getHosts()).get(0));
-
             @Override
             public List<HostToken> getTokens(Set<Host> activeHosts) {
-                return Arrays.asList(token);
+                long i = activeHosts.size();
+                for (Host host : activeHosts) {
+                    HostToken hostToken = new HostToken(i, host);
+                    hostTokens.add(hostToken);
+                    i--;
+                }
+                return hostTokens;
             }
 
             @Override
             public HostToken getTokenForHost(Host host, Set<Host> activeHosts) {
-                return token;
+                return CollectionUtils.find(hostTokens, token -> token.getHost().compareTo(host) == 0);
             }
         };
     }