diff --git a/src/main/java/io/tarantool/driver/api/TarantoolClient.java b/src/main/java/io/tarantool/driver/api/TarantoolClient.java index 7e2833bac..64af7493f 100644 --- a/src/main/java/io/tarantool/driver/api/TarantoolClient.java +++ b/src/main/java/io/tarantool/driver/api/TarantoolClient.java @@ -5,6 +5,8 @@ import io.tarantool.driver.api.metadata.TarantoolMetadataOperations; import io.tarantool.driver.api.metadata.TarantoolMetadataProvider; import io.tarantool.driver.api.space.TarantoolSpaceOperations; +import io.tarantool.driver.core.connection.events.ConnectionManagerEvent; +import io.tarantool.driver.core.connection.events.EventManager; import io.tarantool.driver.exceptions.TarantoolClientException; import io.tarantool.driver.protocol.Packable; @@ -73,10 +75,12 @@ public interface TarantoolClient> */ TarantoolConnectionListeners getConnectionListeners(); + EventManager getEventManager(); + /** * Starts the process of establishing lacking connections to each host * * @return returns true if the establishing process has been started, else false */ - boolean establishLackingConnections(); + boolean refresh(); } diff --git a/src/main/java/io/tarantool/driver/api/TarantoolClientBuilder.java b/src/main/java/io/tarantool/driver/api/TarantoolClientBuilder.java index 6745de94f..11443afb8 100644 --- a/src/main/java/io/tarantool/driver/api/TarantoolClientBuilder.java +++ b/src/main/java/io/tarantool/driver/api/TarantoolClientBuilder.java @@ -4,6 +4,8 @@ import io.tarantool.driver.api.connection.TarantoolConnectionSelectionStrategyType; import io.tarantool.driver.api.tuple.TarantoolTuple; import io.tarantool.driver.auth.TarantoolCredentials; +import io.tarantool.driver.core.connection.events.ConnectionManagerEvent; +import io.tarantool.driver.core.connection.events.EventManager; import io.tarantool.driver.mappers.MessagePackMapper; import java.net.InetSocketAddress; @@ -165,6 +167,8 @@ TarantoolClientBuilder withConnectionSelectionStrategy( TarantoolClientBuilder withConnectionSelectionStrategy( TarantoolConnectionSelectionStrategyType connectionSelectionStrategyType); + TarantoolClientBuilder withConnectionEventManager(EventManager eventManager); + /** * Build the configured Tarantool client instance. Call this when you have specified all necessary settings. * diff --git a/src/main/java/io/tarantool/driver/api/TarantoolClusterAddressProvider.java b/src/main/java/io/tarantool/driver/api/TarantoolClusterAddressProvider.java index 457e90706..488b53152 100644 --- a/src/main/java/io/tarantool/driver/api/TarantoolClusterAddressProvider.java +++ b/src/main/java/io/tarantool/driver/api/TarantoolClusterAddressProvider.java @@ -10,7 +10,8 @@ */ public interface TarantoolClusterAddressProvider extends AutoCloseable { /** - * The the collection of Tarantool server nodes which belong to the same cluster + * The collection of Tarantool server nodes which belong to the same cluster + * * @return collection of {@link TarantoolServerAddress} */ Collection getAddresses(); diff --git a/src/main/java/io/tarantool/driver/cluster/AbstractDiscoveryClusterAddressProvider.java b/src/main/java/io/tarantool/driver/cluster/AbstractDiscoveryClusterAddressProvider.java index 481a2659d..b6a2ea0d3 100644 --- a/src/main/java/io/tarantool/driver/cluster/AbstractDiscoveryClusterAddressProvider.java +++ b/src/main/java/io/tarantool/driver/cluster/AbstractDiscoveryClusterAddressProvider.java @@ -3,6 +3,8 @@ import io.tarantool.driver.api.TarantoolClusterAddressProvider; import io.tarantool.driver.api.TarantoolServerAddress; import io.tarantool.driver.core.TarantoolDaemonThreadFactory; +import io.tarantool.driver.core.connection.events.ConnectionManagerEvent; +import io.tarantool.driver.core.connection.events.EventManager; import io.tarantool.driver.exceptions.TarantoolClientException; import java.util.Collection; @@ -23,9 +25,11 @@ public abstract class AbstractDiscoveryClusterAddressProvider implements Taranto private final ScheduledExecutorService scheduledExecutorService; private final CountDownLatch initLatch = new CountDownLatch(1); private final AtomicReference> addressesHolder = new AtomicReference<>(); + private final EventManager eventManager; public AbstractDiscoveryClusterAddressProvider(TarantoolClusterDiscoveryConfig discoveryConfig) { this.discoveryConfig = discoveryConfig; + this.eventManager = discoveryConfig.getEventManager(); this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( new TarantoolDaemonThreadFactory("tarantool-discovery")); } @@ -33,8 +37,15 @@ public AbstractDiscoveryClusterAddressProvider(TarantoolClusterDiscoveryConfig d protected void startDiscoveryTask() throws TarantoolClientException { Runnable discoveryTask = () -> { try { + Collection currentAddresses = this.addressesHolder.get(); Collection addresses = discoverAddresses(); setAddresses(addresses); + + if (currentAddresses != null + && addresses.size() != currentAddresses.size() + || !addresses.equals(currentAddresses)) { + eventManager.notify(ConnectionManagerEvent.SERVER_ADDRESS_CHANGED); + } } finally { if (initLatch.getCount() > 0) { initLatch.countDown(); diff --git a/src/main/java/io/tarantool/driver/cluster/BinaryClusterDiscoveryEndpoint.java b/src/main/java/io/tarantool/driver/cluster/BinaryClusterDiscoveryEndpoint.java index cccaf7989..a2ab5d62a 100644 --- a/src/main/java/io/tarantool/driver/cluster/BinaryClusterDiscoveryEndpoint.java +++ b/src/main/java/io/tarantool/driver/cluster/BinaryClusterDiscoveryEndpoint.java @@ -72,11 +72,18 @@ public void setDiscoveryFunction(String discoveryFunction) { this.discoveryFunction = discoveryFunction; } + /** + * Builder for {@link BinaryClusterDiscoveryEndpoint} + */ + public static Builder builder() { + return new Builder(); + } + /** * Builder for {@link BinaryClusterDiscoveryEndpoint} */ public static class Builder { - private BinaryClusterDiscoveryEndpoint endpoint; + private final BinaryClusterDiscoveryEndpoint endpoint; /** * Basic constructor. diff --git a/src/main/java/io/tarantool/driver/cluster/HTTPClusterDiscoveryEndpoint.java b/src/main/java/io/tarantool/driver/cluster/HTTPClusterDiscoveryEndpoint.java index 3ebf510ac..0a01d3911 100644 --- a/src/main/java/io/tarantool/driver/cluster/HTTPClusterDiscoveryEndpoint.java +++ b/src/main/java/io/tarantool/driver/cluster/HTTPClusterDiscoveryEndpoint.java @@ -21,6 +21,7 @@ public HTTPClusterDiscoveryEndpoint() { /** * Create an instance, specifying URI for connection + * * @param uri discovery endpoint URI */ public HTTPClusterDiscoveryEndpoint(String uri) { @@ -29,6 +30,7 @@ public HTTPClusterDiscoveryEndpoint(String uri) { /** * Get discovery endpoint URI + * * @return discovery endpoint URI */ public String getUri() { @@ -37,6 +39,7 @@ public String getUri() { /** * Set discovery endpoint URI + * * @param uri discovery endpoint URI */ public void setUri(String uri) { @@ -45,6 +48,7 @@ public void setUri(String uri) { /** * Get cluster discovery endpoint connection timeout + * * @return connection timeout, in milliseconds */ public int getConnectTimeout() { @@ -53,6 +57,7 @@ public int getConnectTimeout() { /** * Set cluster discovery endpoint connection timeout + * * @param connectTimeout connection timeout, in milliseconds */ public void setConnectTimeout(int connectTimeout) { @@ -61,6 +66,7 @@ public void setConnectTimeout(int connectTimeout) { /** * Get response timeout for cluster discovery request + * * @return request timeout, in milliseconds */ public int getReadTimeout() { @@ -69,17 +75,25 @@ public int getReadTimeout() { /** * Set response timeout for cluster discovery request + * * @param readTimeout request timeout, in milliseconds */ public void setReadTimeout(int readTimeout) { this.readTimeout = readTimeout; } + /** + * Builder for {@link HTTPClusterDiscoveryEndpoint} + */ + public static Builder builder() { + return new Builder(); + } + /** * Builder for {@link HTTPClusterDiscoveryEndpoint} */ public static class Builder { - private HTTPClusterDiscoveryEndpoint endpoint; + private final HTTPClusterDiscoveryEndpoint endpoint; /** * Basic constructor. @@ -90,6 +104,7 @@ public Builder() { /** * Specify the cluster discovery endpoint URI + * * @param uri discovery endpoint URI, should not be null or empty * @return this builder instance */ @@ -101,6 +116,7 @@ public Builder withURI(String uri) { /** * Specify the connection timeout for discovery endpoint + * * @param connectTimeout connection timeout, in milliseconds * @return this builder instance * @see HTTPClusterDiscoveryEndpoint#setConnectTimeout(int) @@ -115,6 +131,7 @@ public Builder withConnectTimeout(int connectTimeout) { /** * Specify the read timeout for discovery endpoint connection + * * @param readTimeout timeout of receiving response in the connection, in milliseconds * @return this builder instance * @see HTTPClusterDiscoveryEndpoint#setReadTimeout(int) @@ -129,6 +146,7 @@ public Builder withReadTimeout(int readTimeout) { /** * Build the discovery endpoint configuration + * * @return a {@link HTTPClusterDiscoveryEndpoint} instance */ public HTTPClusterDiscoveryEndpoint build() { diff --git a/src/main/java/io/tarantool/driver/cluster/HTTPDiscoveryClusterAddressProvider.java b/src/main/java/io/tarantool/driver/cluster/HTTPDiscoveryClusterAddressProvider.java index fb7368374..9d25b3873 100644 --- a/src/main/java/io/tarantool/driver/cluster/HTTPDiscoveryClusterAddressProvider.java +++ b/src/main/java/io/tarantool/driver/cluster/HTTPDiscoveryClusterAddressProvider.java @@ -48,7 +48,7 @@ /** * Tarantool server address provider with service discovery via HTTP. * Gets list of nodes from API endpoint in json format. - * + *

* Expected response format example: *

  * 
@@ -68,7 +68,7 @@
  * }
  * 
  * 
- * + *

* Tarantool cartridge application lua http endpoint example: *

  * 
diff --git a/src/main/java/io/tarantool/driver/cluster/TarantoolClusterDiscoveryConfig.java b/src/main/java/io/tarantool/driver/cluster/TarantoolClusterDiscoveryConfig.java
index ab44fe919..ab4fd8e85 100644
--- a/src/main/java/io/tarantool/driver/cluster/TarantoolClusterDiscoveryConfig.java
+++ b/src/main/java/io/tarantool/driver/cluster/TarantoolClusterDiscoveryConfig.java
@@ -1,5 +1,7 @@
 package io.tarantool.driver.cluster;
 
+import io.tarantool.driver.core.connection.events.ConnectionManagerEvent;
+import io.tarantool.driver.core.connection.events.EventManager;
 import io.tarantool.driver.exceptions.TarantoolClientException;
 import io.tarantool.driver.utils.Assert;
 
@@ -14,9 +16,20 @@ public final class TarantoolClusterDiscoveryConfig {
 
     private TarantoolClusterDiscoveryEndpoint endpoint;
     private int serviceDiscoveryDelay = 60_000; // milliseconds
+    private EventManager eventManager = new EventManager<>();
+
+
+    public void setEventManager(EventManager eventManager) {
+        this.eventManager = eventManager;
+    }
+
+    public EventManager getEventManager() {
+        return eventManager;
+    }
 
     /**
      * Get config of service discovery endpoint
+     *
      * @return a {@link TarantoolClusterDiscoveryEndpoint} instance
      */
     public TarantoolClusterDiscoveryEndpoint getEndpoint() {
@@ -25,6 +38,7 @@ public TarantoolClusterDiscoveryEndpoint getEndpoint() {
 
     /**
      * Set service discovery endpoint config and enable cluster connection
+     *
      * @param endpoint a {@link TarantoolClusterDiscoveryEndpoint} instance
      */
     public void setEndpoint(TarantoolClusterDiscoveryEndpoint endpoint) {
@@ -33,6 +47,7 @@ public void setEndpoint(TarantoolClusterDiscoveryEndpoint endpoint) {
 
     /**
      * Get cluster discovery delay
+     *
      * @return cluster discovery delay, milliseconds
      */
     public int getServiceDiscoveryDelay() {
@@ -41,6 +56,7 @@ public int getServiceDiscoveryDelay() {
 
     /**
      * Set scan period (in milliseconds) of receiving a new list of instances
+     *
      * @param serviceDiscoveryDelay period of receiving a new list of instances
      */
     public void setServiceDiscoveryDelay(int serviceDiscoveryDelay) {
@@ -49,6 +65,7 @@ public void setServiceDiscoveryDelay(int serviceDiscoveryDelay) {
 
     /**
      * Create a builder instance.
+     *
      * @return a builder
      */
     public static Builder builder() {
@@ -60,7 +77,7 @@ public static Builder builder() {
      */
     public static class Builder {
 
-        private TarantoolClusterDiscoveryConfig config;
+        private final TarantoolClusterDiscoveryConfig config;
 
         public Builder() {
             this.config = new TarantoolClusterDiscoveryConfig();
@@ -68,6 +85,7 @@ public Builder() {
 
         /**
          * Specify scan period of receiving a new list of instances
+         *
          * @param delay period of receiving a new list of instances, in milliseconds
          * @return this builder instance
          * @see TarantoolClusterDiscoveryConfig#setServiceDiscoveryDelay(int)
@@ -82,6 +100,7 @@ public Builder withDelay(int delay) {
 
         /**
          * Specify service discovery config and enable using service discovery
+         *
          * @param endpoint discovery endpoint config, should not be null
          * @return this builder instance
          * @see TarantoolClusterDiscoveryConfig#setEndpoint(TarantoolClusterDiscoveryEndpoint)
@@ -94,6 +113,7 @@ public Builder withEndpoint(TarantoolClusterDiscoveryEndpoint endpoint) {
 
         /**
          * Build a {@link TarantoolClusterDiscoveryConfig} instance
+         *
          * @return configured instance
          */
         public TarantoolClusterDiscoveryConfig build() {
diff --git a/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java b/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java
index 79dfbe8f7..500f33a1f 100644
--- a/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java
+++ b/src/main/java/io/tarantool/driver/core/AbstractTarantoolClient.java
@@ -149,8 +149,8 @@ private TarantoolConnectionManager connectionManager() {
     }
 
     @Override
-    public boolean establishLackingConnections() {
-        return connectionManager().establishLackingConnections();
+    public boolean refresh() {
+        return connectionManager().refresh();
     }
 
     @Override
diff --git a/src/main/java/io/tarantool/driver/core/ClusterTarantoolClient.java b/src/main/java/io/tarantool/driver/core/ClusterTarantoolClient.java
index f230a5c31..b4104eed8 100644
--- a/src/main/java/io/tarantool/driver/core/ClusterTarantoolClient.java
+++ b/src/main/java/io/tarantool/driver/core/ClusterTarantoolClient.java
@@ -6,6 +6,8 @@
 import io.tarantool.driver.core.connection.TarantoolClusterConnectionManager;
 import io.tarantool.driver.core.connection.TarantoolConnectionFactory;
 import io.tarantool.driver.core.connection.TarantoolConnectionManager;
+import io.tarantool.driver.core.connection.events.ConnectionManagerEvent;
+import io.tarantool.driver.core.connection.events.EventManager;
 import io.tarantool.driver.protocol.Packable;
 import io.tarantool.driver.utils.Assert;
 
@@ -25,6 +27,18 @@ public abstract class ClusterTarantoolClient {
 
     private final TarantoolClusterAddressProvider addressProvider;
+    private final EventManager eventManager;
+
+    public ClusterTarantoolClient(TarantoolClientConfig config,
+                                  TarantoolClusterAddressProvider addressProvider,
+                                  EventManager eventManager) {
+        super(config);
+
+        Assert.notNull(addressProvider, "Address provider must not be null");
+
+        this.addressProvider = addressProvider;
+        this.eventManager = eventManager;
+    }
 
     /**
      * Create a client. The server address for connecting to the server is specified by the passed address provider.
@@ -35,21 +49,23 @@ public abstract class ClusterTarantoolClient());
     }
 
     @Override
     protected TarantoolConnectionManager connectionManager(TarantoolClientConfig config,
                                                            TarantoolConnectionFactory connectionFactory,
                                                            TarantoolConnectionListeners listeners) {
-        return new TarantoolClusterConnectionManager(config, connectionFactory, listeners, addressProvider);
+        return new TarantoolClusterConnectionManager(
+                config, connectionFactory, listeners, addressProvider, eventManager);
     }
 
     protected TarantoolClusterAddressProvider getAddressProvider() {
         return addressProvider;
     }
+
+    @Override
+    public EventManager getEventManager() {
+        return eventManager;
+    }
 }
diff --git a/src/main/java/io/tarantool/driver/core/ClusterTarantoolTupleClient.java b/src/main/java/io/tarantool/driver/core/ClusterTarantoolTupleClient.java
index c292eb421..2ba5a73fb 100644
--- a/src/main/java/io/tarantool/driver/core/ClusterTarantoolTupleClient.java
+++ b/src/main/java/io/tarantool/driver/core/ClusterTarantoolTupleClient.java
@@ -12,6 +12,8 @@
 import io.tarantool.driver.auth.SimpleTarantoolCredentials;
 import io.tarantool.driver.auth.TarantoolCredentials;
 import io.tarantool.driver.core.connection.TarantoolConnectionManager;
+import io.tarantool.driver.core.connection.events.ConnectionManagerEvent;
+import io.tarantool.driver.core.connection.events.EventManager;
 import io.tarantool.driver.core.space.TarantoolTupleSpace;
 
 import java.util.Collection;
@@ -138,6 +140,19 @@ public ClusterTarantoolTupleClient(TarantoolClientConfig config, TarantoolCluste
         super(config, addressProvider);
     }
 
+    /**
+     * Create a client. Connect using the list of Tarantool servers returned by the specified server address provider.
+     *
+     * @param config          client configuration
+     * @param addressProvider provides Tarantool server address for connection
+     * @param eventManager todo:
+     * @see TarantoolClientConfig
+     */
+    public ClusterTarantoolTupleClient(TarantoolClientConfig config, TarantoolClusterAddressProvider addressProvider,
+                                       EventManager eventManager) {
+        super(config, addressProvider, eventManager);
+    }
+
     @Override
     protected TarantoolSpaceOperations>
     spaceOperations(TarantoolClientConfig config, TarantoolConnectionManager connectionManager,
diff --git a/src/main/java/io/tarantool/driver/core/ProxyTarantoolClient.java b/src/main/java/io/tarantool/driver/core/ProxyTarantoolClient.java
index 67d53efe0..a7dc4f6e8 100644
--- a/src/main/java/io/tarantool/driver/core/ProxyTarantoolClient.java
+++ b/src/main/java/io/tarantool/driver/core/ProxyTarantoolClient.java
@@ -14,6 +14,8 @@
 import io.tarantool.driver.api.metadata.TarantoolSpaceMetadata;
 import io.tarantool.driver.api.proxy.ProxyOperationsMappingConfig;
 import io.tarantool.driver.api.space.TarantoolSpaceOperations;
+import io.tarantool.driver.core.connection.events.ConnectionManagerEvent;
+import io.tarantool.driver.core.connection.events.EventManager;
 import io.tarantool.driver.core.metadata.DDLTarantoolSpaceMetadataConverter;
 import io.tarantool.driver.core.metadata.ProxyMetadataProvider;
 import io.tarantool.driver.core.metadata.TarantoolMetadata;
@@ -417,8 +419,13 @@ public CompletableFuture> eval(String expression,
     }
 
     @Override
-    public boolean establishLackingConnections() {
-        return this.client.establishLackingConnections();
+    public boolean refresh() {
+        return this.client.refresh();
+    }
+
+    @Override
+    public EventManager getEventManager() {
+        return this.client.getEventManager();
     }
 
     @Override
diff --git a/src/main/java/io/tarantool/driver/core/RetryingTarantoolClient.java b/src/main/java/io/tarantool/driver/core/RetryingTarantoolClient.java
index 5c50c51d0..cac0b6ea2 100644
--- a/src/main/java/io/tarantool/driver/core/RetryingTarantoolClient.java
+++ b/src/main/java/io/tarantool/driver/core/RetryingTarantoolClient.java
@@ -12,6 +12,8 @@
 import io.tarantool.driver.api.retry.RequestRetryPolicy;
 import io.tarantool.driver.api.retry.RequestRetryPolicyFactory;
 import io.tarantool.driver.api.space.TarantoolSpaceOperations;
+import io.tarantool.driver.core.connection.events.ConnectionManagerEvent;
+import io.tarantool.driver.core.connection.events.EventManager;
 import io.tarantool.driver.core.space.RetryingTarantoolSpace;
 import io.tarantool.driver.exceptions.TarantoolClientException;
 import io.tarantool.driver.mappers.CallResultMapper;
@@ -379,8 +381,13 @@ public CompletableFuture> eval(String expression, List arguments,
     }
 
     @Override
-    public boolean establishLackingConnections() {
-        return this.client.establishLackingConnections();
+    public boolean refresh() {
+        return this.client.refresh();
+    }
+
+    @Override
+    public EventManager getEventManager() {
+        return this.client.getEventManager();
     }
 
     @Override
diff --git a/src/main/java/io/tarantool/driver/core/TarantoolClientBuilderImpl.java b/src/main/java/io/tarantool/driver/core/TarantoolClientBuilderImpl.java
index 0c5a90d3d..9fbe54a3a 100644
--- a/src/main/java/io/tarantool/driver/core/TarantoolClientBuilderImpl.java
+++ b/src/main/java/io/tarantool/driver/core/TarantoolClientBuilderImpl.java
@@ -11,6 +11,8 @@
 import io.tarantool.driver.api.tuple.TarantoolTuple;
 import io.tarantool.driver.auth.SimpleTarantoolCredentials;
 import io.tarantool.driver.auth.TarantoolCredentials;
+import io.tarantool.driver.core.connection.events.ConnectionManagerEvent;
+import io.tarantool.driver.core.connection.events.EventManager;
 import io.tarantool.driver.mappers.MessagePackMapper;
 
 import java.net.InetSocketAddress;
@@ -28,10 +30,12 @@ public class TarantoolClientBuilderImpl extends TarantoolClientConfiguratorImpl<
 
     private final TarantoolClientConfig.Builder configBuilder;
     private TarantoolClusterAddressProvider addressProvider;
+    private EventManager eventManager;
 
     public TarantoolClientBuilderImpl() {
         this.configBuilder = TarantoolClientConfig.builder();
         this.addressProvider = () -> Collections.singleton(new TarantoolServerAddress());
+        this.eventManager = new EventManager<>();
     }
 
     @Override
@@ -119,8 +123,17 @@ public TarantoolClientBuilder withConnectionSelectionStrategy(
         return this;
     }
 
+    @Override
+    public TarantoolClientBuilder withConnectionEventManager(EventManager eventManager) {
+        this.eventManager = eventManager;
+        return this;
+    }
+
     @Override
     public TarantoolClient> build() {
-        return super.decorate(new ClusterTarantoolTupleClient(this.configBuilder.build(), this.addressProvider));
+        final ClusterTarantoolTupleClient client =
+                new ClusterTarantoolTupleClient(this.configBuilder.build(), this.addressProvider, this.eventManager);
+
+        return super.decorate(client);
     }
 }
diff --git a/src/main/java/io/tarantool/driver/core/connection/AbstractTarantoolConnectionManager.java b/src/main/java/io/tarantool/driver/core/connection/AbstractTarantoolConnectionManager.java
index b6bb7f479..c8349b0a4 100644
--- a/src/main/java/io/tarantool/driver/core/connection/AbstractTarantoolConnectionManager.java
+++ b/src/main/java/io/tarantool/driver/core/connection/AbstractTarantoolConnectionManager.java
@@ -6,6 +6,8 @@
 import io.tarantool.driver.api.connection.ConnectionSelectionStrategyFactory;
 import io.tarantool.driver.api.connection.TarantoolConnection;
 import io.tarantool.driver.api.connection.TarantoolConnectionListeners;
+import io.tarantool.driver.core.connection.events.ConnectionManagerEvent;
+import io.tarantool.driver.core.connection.events.EventManager;
 import io.tarantool.driver.exceptions.NoAvailableConnectionsException;
 import io.tarantool.driver.exceptions.TarantoolClientException;
 import io.tarantool.driver.exceptions.TarantoolConnectionException;
@@ -14,6 +16,7 @@
 
 import java.util.AbstractMap;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -42,42 +45,32 @@ public abstract class AbstractTarantoolConnectionManager implements TarantoolCon
     private final AtomicReference connectionSelectStrategy = new AtomicReference<>();
     // connection init sequence state
     private final AtomicReference connectionMode = new AtomicReference<>(ConnectionMode.FULL);
+    private final EventManager eventManager;
     // resettable barrier for preventing multiple threads from running into the connection init sequence
     private final Phaser initPhaser = new Phaser(0);
     private final Logger logger = LoggerFactory.getLogger(getClass().getName());
 
-    /**
-     * Constructor
-     *
-     * @param config                   Tarantool client config
-     * @param connectionFactory        connection factory
-     * @param selectionStrategyFactory connection selection strategy factory
-     * @param connectionListeners      connection listeners
-     * @deprecated
-     */
-    protected AbstractTarantoolConnectionManager(TarantoolClientConfig config,
-                                                 TarantoolConnectionFactory connectionFactory,
-                                                 ConnectionSelectionStrategyFactory selectionStrategyFactory,
-                                                 TarantoolConnectionListeners connectionListeners) {
-        this(config, connectionFactory, connectionListeners);
-    }
-
     /**
      * Basic constructor
      *
      * @param config              Tarantool client config
      * @param connectionFactory   connection factory
      * @param connectionListeners connection listeners
+     * @param eventManager        event manager
      */
     public AbstractTarantoolConnectionManager(TarantoolClientConfig config,
                                               TarantoolConnectionFactory connectionFactory,
-                                              TarantoolConnectionListeners connectionListeners) {
+                                              TarantoolConnectionListeners connectionListeners,
+                                              EventManager eventManager) {
         this.config = config;
         this.connectionFactory = connectionFactory;
         this.selectStrategyFactory = config.getConnectionSelectionStrategyFactory();
         this.connectionSelectStrategy.set(selectStrategyFactory.create(config, Collections.emptyList()));
         this.connectionListeners = connectionListeners;
         this.connectionRegistry = new HashMap<>();
+        this.eventManager = eventManager;
+
+        eventManager.subscribe(ConnectionManagerEvent.SERVER_ADDRESS_CHANGED, this::refresh);
     }
 
     /**
@@ -105,7 +98,7 @@ public CompletableFuture getConnection() {
     }
 
     @Override
-    public boolean establishLackingConnections() {
+    public boolean refresh() {
         return connectionMode.compareAndSet(ConnectionMode.OFF, ConnectionMode.PARTIAL);
     }
 
@@ -266,6 +259,7 @@ public void close() {
         if (initPhaser.getRegisteredParties() > 0) {
             initPhaser.awaitAdvance(initPhaser.getPhase());
         }
+
         connectionRegistry.values().stream()
                 .flatMap(Collection::stream)
                 .forEach(conn -> {
@@ -275,5 +269,8 @@ public void close() {
                         logger.warn("Failed to close connection: {}", e.getMessage());
                     }
                 });
+
+        Arrays.asList(ConnectionManagerEvent.values())
+                .forEach(eventManager::unsubscribe);
     }
 }
diff --git a/src/main/java/io/tarantool/driver/core/connection/TarantoolClusterConnectionManager.java b/src/main/java/io/tarantool/driver/core/connection/TarantoolClusterConnectionManager.java
index d588b1b27..eb7629b2a 100644
--- a/src/main/java/io/tarantool/driver/core/connection/TarantoolClusterConnectionManager.java
+++ b/src/main/java/io/tarantool/driver/core/connection/TarantoolClusterConnectionManager.java
@@ -4,6 +4,8 @@
 import io.tarantool.driver.api.TarantoolClusterAddressProvider;
 import io.tarantool.driver.api.TarantoolServerAddress;
 import io.tarantool.driver.api.connection.TarantoolConnectionListeners;
+import io.tarantool.driver.core.connection.events.ConnectionManagerEvent;
+import io.tarantool.driver.core.connection.events.EventManager;
 
 import java.util.Collection;
 
@@ -26,8 +28,9 @@ public class TarantoolClusterConnectionManager extends AbstractTarantoolConnecti
     public TarantoolClusterConnectionManager(TarantoolClientConfig config,
                                              TarantoolConnectionFactory connectionFactory,
                                              TarantoolConnectionListeners listeners,
-                                             TarantoolClusterAddressProvider addressProvider) {
-        super(config, connectionFactory, listeners);
+                                             TarantoolClusterAddressProvider addressProvider,
+                                             EventManager eventManager) {
+        super(config, connectionFactory, listeners, eventManager);
         this.addressProvider = addressProvider;
     }
 
diff --git a/src/main/java/io/tarantool/driver/core/connection/TarantoolConnectionManager.java b/src/main/java/io/tarantool/driver/core/connection/TarantoolConnectionManager.java
index e64968242..941bd216a 100644
--- a/src/main/java/io/tarantool/driver/core/connection/TarantoolConnectionManager.java
+++ b/src/main/java/io/tarantool/driver/core/connection/TarantoolConnectionManager.java
@@ -24,5 +24,5 @@ public interface TarantoolConnectionManager extends AutoCloseable {
      *
      * @return returns true if the establishing process has been started, else false
      */
-    boolean establishLackingConnections();
+    boolean refresh();
 }
diff --git a/src/main/java/io/tarantool/driver/core/connection/events/ConnectionManagerEvent.java b/src/main/java/io/tarantool/driver/core/connection/events/ConnectionManagerEvent.java
new file mode 100644
index 000000000..8ebdff080
--- /dev/null
+++ b/src/main/java/io/tarantool/driver/core/connection/events/ConnectionManagerEvent.java
@@ -0,0 +1,6 @@
+package io.tarantool.driver.core.connection.events;
+
+public enum ConnectionManagerEvent {
+
+    SERVER_ADDRESS_CHANGED
+}
diff --git a/src/main/java/io/tarantool/driver/core/connection/events/EventListener.java b/src/main/java/io/tarantool/driver/core/connection/events/EventListener.java
new file mode 100644
index 000000000..04819b615
--- /dev/null
+++ b/src/main/java/io/tarantool/driver/core/connection/events/EventListener.java
@@ -0,0 +1,6 @@
+package io.tarantool.driver.core.connection.events;
+
+public interface EventListener {
+
+    void update();
+}
diff --git a/src/main/java/io/tarantool/driver/core/connection/events/EventManager.java b/src/main/java/io/tarantool/driver/core/connection/events/EventManager.java
new file mode 100644
index 000000000..d6c5df519
--- /dev/null
+++ b/src/main/java/io/tarantool/driver/core/connection/events/EventManager.java
@@ -0,0 +1,37 @@
+package io.tarantool.driver.core.connection.events;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class EventManager> {
+
+    private final Map> listeners;
+
+    public EventManager() {
+        this.listeners = new HashMap<>();
+    }
+
+    public void subscribe(E type, EventListener listener) {
+        Set eventListeners = listeners.computeIfAbsent(type, k -> new HashSet<>());
+        eventListeners.add(listener);
+    }
+
+    public void unsubscribe(E type, EventListener listener) {
+        final Set eventListeners = listeners.get(type);
+        if (eventListeners != null) {
+            eventListeners.remove(listener);
+        }
+    }
+
+    public void unsubscribe(E type) {
+        listeners.remove(type);
+    }
+
+    public void notify(E type) {
+        listeners.forEach((key, eventListeners) -> {
+            eventListeners.forEach(EventListener::update);
+        });
+    }
+}
diff --git a/src/test/java/io/tarantool/driver/cluster/TestWrappedClusterAddressProvider.java b/src/test/java/io/tarantool/driver/cluster/TestWrappedClusterAddressProvider.java
index bd5454322..bb2997291 100644
--- a/src/test/java/io/tarantool/driver/cluster/TestWrappedClusterAddressProvider.java
+++ b/src/test/java/io/tarantool/driver/cluster/TestWrappedClusterAddressProvider.java
@@ -5,6 +5,7 @@
 import org.testcontainers.containers.TarantoolCartridgeContainer;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.stream.Collectors;
 
 public class TestWrappedClusterAddressProvider implements TarantoolClusterAddressProvider {
@@ -22,11 +23,15 @@ public TestWrappedClusterAddressProvider(TarantoolClusterAddressProvider provide
     public Collection getAddresses() {
         Collection addresses = provider.getAddresses();
 
+        if (addresses == null) {
+            return Collections.emptyList();
+        }
+
         return addresses.stream().map(a ->
-            new TarantoolServerAddress(
-                    a.getHost(),
-                    container.getMappedPort(a.getPort())
-            )
+                new TarantoolServerAddress(
+                        a.getHost(),
+                        container.getMappedPort(a.getPort())
+                )
         ).collect(Collectors.toList());
     }
 }
diff --git a/src/test/java/io/tarantool/driver/integration/ClusterConnectionIT.java b/src/test/java/io/tarantool/driver/integration/ClusterConnectionIT.java
index 5b766c18d..66adb1cab 100644
--- a/src/test/java/io/tarantool/driver/integration/ClusterConnectionIT.java
+++ b/src/test/java/io/tarantool/driver/integration/ClusterConnectionIT.java
@@ -1,14 +1,14 @@
 package io.tarantool.driver.integration;
 
-import io.tarantool.driver.core.ClusterTarantoolTupleClient;
-import io.tarantool.driver.core.ProxyTarantoolTupleClient;
-import io.tarantool.driver.core.RetryingTarantoolTupleClient;
 import io.tarantool.driver.api.TarantoolClientConfig;
 import io.tarantool.driver.api.TarantoolClusterAddressProvider;
-import io.tarantool.driver.api.retry.TarantoolRequestRetryPolicies;
 import io.tarantool.driver.api.TarantoolServerAddress;
-import io.tarantool.driver.auth.SimpleTarantoolCredentials;
 import io.tarantool.driver.api.connection.TarantoolConnection;
+import io.tarantool.driver.api.retry.TarantoolRequestRetryPolicies;
+import io.tarantool.driver.auth.SimpleTarantoolCredentials;
+import io.tarantool.driver.core.ClusterTarantoolTupleClient;
+import io.tarantool.driver.core.ProxyTarantoolTupleClient;
+import io.tarantool.driver.core.RetryingTarantoolTupleClient;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.rnorth.ducttape.unreliables.Unreliables;
@@ -28,7 +28,9 @@
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * @author Alexey Kuzin
@@ -137,7 +139,7 @@ void testMultipleRoutersReconnect_retryableRequestShouldNotFail() throws Excepti
         // after the first retry we will turn off this router
         // and it is expected that the request will go to another router
         assertTrue(client.callForSingleResult("long_running_function",
-                        Collections.singletonList(Arrays.asList(0.5, nextRouterName.get())), Boolean.class).get());
+                Collections.singletonList(Arrays.asList(0.5, nextRouterName.get())), Boolean.class).get());
 
         // start the turned off router to get requests
         result.set(container.execInContainer(
@@ -232,20 +234,20 @@ void testMultipleConnectionsReconnect_retryableRequestShouldNotFail() throws Exc
 
         // initiate another long-running request
         request1 = client.callForSingleResult("long_running_function", Collections.singletonList(0.5), Boolean.class)
-        .thenApply(r -> {
-            try {
-                // partial disconnect -> one connection is restored
-                assertEquals(3, connections.size());
-
-                // close remaining connections
-                for (int i = 1; i < 3; i++) {
-                    connections.get(i).close();
-                }
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-            return r;
-        });
+                .thenApply(r -> {
+                    try {
+                        // partial disconnect -> one connection is restored
+                        assertEquals(3, connections.size());
+
+                        // close remaining connections
+                        for (int i = 1; i < 3; i++) {
+                            connections.get(i).close();
+                        }
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                    return r;
+                });
 
         // the request should return normally (reconnection effect)
         assertTrue(request1.get());
diff --git a/src/test/java/io/tarantool/driver/integration/ClusterDiscoveryIT.java b/src/test/java/io/tarantool/driver/integration/ClusterDiscoveryIT.java
index 776bd91aa..754930747 100644
--- a/src/test/java/io/tarantool/driver/integration/ClusterDiscoveryIT.java
+++ b/src/test/java/io/tarantool/driver/integration/ClusterDiscoveryIT.java
@@ -1,17 +1,17 @@
 package io.tarantool.driver.integration;
 
-import io.tarantool.driver.core.ClusterTarantoolTupleClient;
 import io.tarantool.driver.api.TarantoolClientConfig;
 import io.tarantool.driver.api.TarantoolClusterAddressProvider;
 import io.tarantool.driver.api.TarantoolServerAddress;
+import io.tarantool.driver.auth.SimpleTarantoolCredentials;
+import io.tarantool.driver.auth.TarantoolCredentials;
 import io.tarantool.driver.cluster.BinaryClusterDiscoveryEndpoint;
 import io.tarantool.driver.cluster.BinaryDiscoveryClusterAddressProvider;
-import io.tarantool.driver.cluster.TarantoolClusterDiscoveryConfig;
 import io.tarantool.driver.cluster.HTTPClusterDiscoveryEndpoint;
 import io.tarantool.driver.cluster.HTTPDiscoveryClusterAddressProvider;
-import io.tarantool.driver.auth.SimpleTarantoolCredentials;
-import io.tarantool.driver.auth.TarantoolCredentials;
+import io.tarantool.driver.cluster.TarantoolClusterDiscoveryConfig;
 import io.tarantool.driver.cluster.TestWrappedClusterAddressProvider;
+import io.tarantool.driver.core.ClusterTarantoolTupleClient;
 import io.tarantool.driver.exceptions.TarantoolClientException;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
@@ -21,7 +21,9 @@
 import java.util.HashSet;
 import java.util.Set;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * @author Sergey Volgin
diff --git a/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientMixedInstancesIT.java b/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientMixedInstancesIT.java
index d87b791c4..06e0a2877 100644
--- a/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientMixedInstancesIT.java
+++ b/src/test/java/io/tarantool/driver/integration/ProxyTarantoolClientMixedInstancesIT.java
@@ -42,7 +42,6 @@
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
-import java.util.function.Function;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -116,7 +115,7 @@ public static void initClient() {
         ClusterTarantoolTupleClient clusterClient = new ClusterTarantoolTupleClient(
                 config, getClusterAddressProvider());
 
-        client =  new RetryingTarantoolTupleClient(new ProxyTarantoolTupleClient(clusterClient),
+        client = new RetryingTarantoolTupleClient(new ProxyTarantoolTupleClient(clusterClient),
                 TarantoolRequestRetryPolicies.AttemptsBoundRetryPolicyFactory
                         .builder(10, thr -> thr instanceof TarantoolNoSuchProcedureException)
                         .withDelay(100)
diff --git a/src/test/java/io/tarantool/driver/integration/ReconnectIT.java b/src/test/java/io/tarantool/driver/integration/ReconnectIT.java
index 105337d0f..40dc213d2 100644
--- a/src/test/java/io/tarantool/driver/integration/ReconnectIT.java
+++ b/src/test/java/io/tarantool/driver/integration/ReconnectIT.java
@@ -1,11 +1,21 @@
 package io.tarantool.driver.integration;
 
 import io.tarantool.driver.api.TarantoolClient;
+import io.tarantool.driver.api.TarantoolClientConfig;
 import io.tarantool.driver.api.TarantoolClientFactory;
 import io.tarantool.driver.api.TarantoolResult;
 import io.tarantool.driver.api.TarantoolServerAddress;
+import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory;
 import io.tarantool.driver.api.tuple.TarantoolTuple;
+import io.tarantool.driver.api.tuple.TarantoolTupleFactory;
+import io.tarantool.driver.auth.SimpleTarantoolCredentials;
+import io.tarantool.driver.cluster.BinaryClusterDiscoveryEndpoint;
+import io.tarantool.driver.cluster.BinaryDiscoveryClusterAddressProvider;
+import io.tarantool.driver.cluster.TarantoolClusterDiscoveryConfig;
+import io.tarantool.driver.cluster.TestWrappedClusterAddressProvider;
 import io.tarantool.driver.exceptions.TarantoolNoSuchProcedureException;
+import io.tarantool.driver.mappers.DefaultMessagePackMapperFactory;
+import org.jetbrains.annotations.NotNull;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
@@ -13,8 +23,10 @@
 import org.testcontainers.containers.output.WaitingConsumer;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.CompletionException;
 import java.util.concurrent.TimeoutException;
 
@@ -32,6 +44,10 @@ public class ReconnectIT extends SharedCartridgeContainer {
     private static String USER_NAME;
     private static String PASSWORD;
 
+    private static final DefaultMessagePackMapperFactory mapperFactory = DefaultMessagePackMapperFactory.getInstance();
+    private static final TarantoolTupleFactory tupleFactory =
+            new DefaultTarantoolTupleFactory(mapperFactory.defaultComplexTypesMapper());
+
     @BeforeAll
     public static void setUp() throws TimeoutException {
         startCluster();
@@ -109,7 +125,7 @@ public void test_should_reconnect_ifReconnectIsInvoked() throws Exception {
         // start routers
         container.execInContainer("cartridge", "start", "--run-dir=/tmp/run", "--data-dir=/tmp/data", "-d");
 
-        client.establishLackingConnections();
+        client.refresh();
         Thread.sleep(3000);
 
         // getting all routers uuids after restarting
@@ -136,6 +152,83 @@ private TarantoolClient> getRetr
                 .build();
     }
 
+    @Test
+    void should_removeUnavailableHostsFromAddressProvider_ifDiscoveryProcedureReturnStatusNotHealthyAndNotAvailable() throws InterruptedException {
+        initRouterStatuses();
+        final TarantoolClient> client = initClientWithDiscovery();
+
+        final Set instancesUuids = getInstancesUuids(client);
+        assertEquals(3, instancesUuids.size());
+
+        replaceInstancesInfo(client, 1, "unavailable", 3301);
+        replaceInstancesInfo(client, 2, "unavailable", 3311);
+        Thread.sleep(1000);
+
+        final Set afterRoutersDisablingInstancesUuids = getInstancesUuids(client);
+        assertEquals(1, afterRoutersDisablingInstancesUuids.size());
+
+        replaceInstancesInfo(client, 1, "available", 3301);
+        replaceInstancesInfo(client, 2, "available", 3311);
+        Thread.sleep(1000);
+
+        final Set afterRoutersEnablingInstancesUuids = getInstancesUuids(client);
+        assertEquals(3, afterRoutersEnablingInstancesUuids.size());
+    }
+
+    private TarantoolClient> initClientWithDiscovery() {
+        final TarantoolClusterDiscoveryConfig clusterDiscoveryConfig = TarantoolClusterDiscoveryConfig.builder()
+                .withEndpoint(
+                        BinaryClusterDiscoveryEndpoint.builder()
+                                .withEntryFunction("get_routers_status")
+                                .withEndpointProvider(() -> Arrays.asList(getTarantoolServerAddresses()))
+                                .withClientConfig(TarantoolClientConfig.builder()
+                                        .withCredentials(new SimpleTarantoolCredentials(USER_NAME, PASSWORD))
+                                        .build()
+                                )
+                                .build()
+                )
+                .withDelay(50)
+                .build();
+        final BinaryDiscoveryClusterAddressProvider binaryDiscoveryClusterAddressProvider =
+                new BinaryDiscoveryClusterAddressProvider(clusterDiscoveryConfig);
+
+        final TarantoolClient> client =
+                TarantoolClientFactory.createClient()
+                        .withAddressProvider(
+                                new TestWrappedClusterAddressProvider(binaryDiscoveryClusterAddressProvider, container))
+                        .withCredentials(USER_NAME, PASSWORD)
+                        .withConnections(10)
+                        .withProxyMethodMapping()
+                        .withConnectionEventManager(clusterDiscoveryConfig.getEventManager())
+                        .build();
+        return client;
+    }
+
+    private void initRouterStatuses() {
+        final TarantoolClient> initClient =
+                TarantoolClientFactory.createClient()
+                        .withAddresses(getTarantoolServerAddresses())
+                        .withCredentials(USER_NAME, PASSWORD)
+                        .withConnections(1)
+                        .build();
+        initClient.call("init_router_status").join();
+    }
+
+    private void replaceInstancesInfo(TarantoolClient> client,
+                                      int id, String status, Integer port) {
+        final TarantoolTuple tuple = tupleFactory
+                .create(id, 1, UUID.randomUUID().toString(), status, String.format("%s:%s", "localhost", port));
+
+        client.space("instances_info").replace(tuple).join();
+    }
+
+    @NotNull
+    private TarantoolServerAddress[] getTarantoolServerAddresses() {
+        return new TarantoolServerAddress[]{new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3301)),
+                new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3311)),
+                new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3312))};
+    }
+
     /**
      * Return all instances uuids from cluster, using round robin connection selection strategy
      *
@@ -145,16 +238,16 @@ private TarantoolClient> getRetr
     private Set getInstancesUuids(TarantoolClient> client) {
         String firstUuid = getInstanceUuid(client);
 
-        final Set routerUuids = new HashSet<>();
-        routerUuids.add(firstUuid);
+        final Set instancesUuids = new HashSet<>();
+        instancesUuids.add(firstUuid);
 
         String currentUuid = "";
         while (!firstUuid.equals(currentUuid)) {
             currentUuid = getInstanceUuid(client);
-            routerUuids.add(currentUuid);
+            instancesUuids.add(currentUuid);
         }
 
-        return routerUuids;
+        return instancesUuids;
     }
 
     private String getInstanceUuid(TarantoolClient> client) {
diff --git a/src/test/resources/cartridge/app/roles/api_router.lua b/src/test/resources/cartridge/app/roles/api_router.lua
index da2bbcde7..d5994c16e 100644
--- a/src/test/resources/cartridge/app/roles/api_router.lua
+++ b/src/test/resources/cartridge/app/roles/api_router.lua
@@ -2,7 +2,9 @@ local vshard = require('vshard')
 local cartridge_rpc = require('cartridge.rpc')
 local fiber = require('fiber')
 local crud = require('crud')
+local uuid = require('uuid')
 local log = require('log')
+local json = require('json')
 
 local function get_schema()
     for _, instance_uri in pairs(cartridge_rpc.get_candidates('app.roles.api_storage', { leader_only = true })) do
@@ -14,6 +16,24 @@ local function truncate_space(space_name)
     crud.truncate(space_name)
 end
 
+local function get_routers_status()
+    local res = crud.select('instances_info')
+
+    local result = {}
+    for k, v in pairs(res.rows) do
+        result[v[3]] = { status = v[4], uri = v[5] }
+    end
+    log.error(json.encode(res))
+    log.error(json.encode(result))
+    return result
+end
+
+local function init_router_status()
+    crud.insert('instances_info', { 1, 1, uuid.str(), 'available', 'localhost:3301' })
+    crud.insert('instances_info', { 2, 1, uuid.str(), 'available', 'localhost:3311' })
+    crud.insert('instances_info', { 3, 1, uuid.str(), 'available', 'localhost:3312' })
+end
+
 local retries_holder = {
 }
 local function setup_retrying_function(retries)
@@ -158,6 +178,8 @@ local function init(opts)
     rawset(_G, 'box_error_non_network_error', box_error_non_network_error)
     rawset(_G, 'crud_error_timeout', crud_error_timeout)
     rawset(_G, 'custom_crud_select', custom_crud_select)
+    rawset(_G, 'get_routers_status', get_routers_status)
+    rawset(_G, 'init_router_status', init_router_status)
     rawset(_G, 'test_no_such_procedure', test_no_such_procedure)
 
     return true
diff --git a/src/test/resources/cartridge/app/roles/api_storage.lua b/src/test/resources/cartridge/app/roles/api_storage.lua
index 132cd6080..c2017f6f0 100644
--- a/src/test/resources/cartridge/app/roles/api_storage.lua
+++ b/src/test/resources/cartridge/app/roles/api_storage.lua
@@ -81,6 +81,23 @@ local function init_space()
     test_space_with_double_field:create_index('id', { parts = { 'id' }, if_not_exists = true, })
     test_space_with_double_field:create_index('bucket_id', { parts = { 'bucket_id' }, unique = false, if_not_exists = true, })
 
+    local instances_info = box.schema.space.create(
+            'instances_info',
+            {
+                format = {
+                    { 'id', 'unsigned' },
+                    { 'bucket_id', 'unsigned' },
+                    { 'uuid', 'string' },
+                    { 'status', 'string' },
+                    { 'uri', 'string' },
+                },
+                if_not_exists = true,
+            }
+    )
+
+    instances_info:create_index('id', { parts = { 'id' }, if_not_exists = true, })
+    instances_info:create_index('bucket_id', { parts = { 'bucket_id' }, unique = false, if_not_exists = true, })
+
     -- cursor test spaces
     local cursor_test_space = box.schema.space.create('cursor_test_space', { if_not_exists = true })
     cursor_test_space:format({