BUG-7222: Make BGP DS clean up asynchronous 93/51893/3
authorClaudio D. Gasparini <claudio.gasparini@pantheon.tech>
Wed, 15 Feb 2017 08:58:38 +0000 (09:58 +0100)
committerClaudio D. Gasparini <claudio.gasparini@pantheon.tech>
Thu, 16 Feb 2017 13:04:14 +0000 (14:04 +0100)
Close of the service must be done async, otherwise
will bock the thread.
Fix by make BGP DS clean up asynchronous

Change-Id: Icb19ef7b7f118fbc6b07407d1df2cb5f6cffc0fb
Signed-off-by: Claudio D. Gasparini <claudio.gasparini@pantheon.tech>
13 files changed:
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AdjRibInWriter.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeer.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BGPPeer.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/AppPeer.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/BgpPeer.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/PeerTest.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/SimpleSessionListener.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/StrictBGPPeerRegistryTest.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/BGPSessionListener.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/Peer.java
bgp/testtool/src/main/java/org/opendaylight/protocol/bgp/testtool/TestingListener.java
bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/AbstractTopologyBuilder.java
bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/config/TopologyReferenceSingletonServiceImpl.java

index 6e6dee5e6e87f1d56eadff6d7c90bb26e1b607ac..11e96da6914a4fc397ee130dc36a134f8a745299 100644 (file)
@@ -11,8 +11,10 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -252,17 +254,25 @@ final class AdjRibInWriter {
         return pb.build();
     }
 
-    void removePeer() {
+    ListenableFuture<Void> removePeer() {
         if(this.peerPath != null) {
             final DOMDataWriteTransaction tx = this.chain.newWriteOnlyTransaction();
             tx.delete(LogicalDatastoreType.OPERATIONAL, this.peerPath);
+            final CheckedFuture<Void, TransactionCommitFailedException> future = tx.submit();
+            Futures.addCallback(future, new FutureCallback<Void>() {
+                @Override
+                public void onSuccess(final Void result) {
+                    LOG.debug("Peer {} removed", AdjRibInWriter.this.peerPath);
+                }
 
-            try {
-                tx.submit().checkedGet();
-            } catch (final TransactionCommitFailedException e) {
-                LOG.debug("Failed to remove Peer {}", this.peerPath, e);
-            }
+                @Override
+                public void onFailure(final Throwable t) {
+                    LOG.warn("Failed to remove Peer {}", AdjRibInWriter.this.peerPath, t);
+                }
+            });
+            return future;
         }
+        return Futures.immediateFuture(null);
     }
 
     void markTableUptodate(final TablesKey tableTypes) {
index 3a02b9b7898dfe584c561b9882ff9a7be0c6d328..45c3c1a2eb742f72cf0edebfffc999d11407497a 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.protocol.bgp.rib.impl;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Verify;
 import com.google.common.net.InetAddresses;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -73,8 +75,8 @@ import org.slf4j.LoggerFactory;
  * For purposed of import policies such as Best Path Selection, application
  * peer needs to have a BGP-ID that is configurable.
  */
-public class ApplicationPeer extends BGPPeerStateImpl implements AutoCloseable,
-    org.opendaylight.protocol.bgp.rib.spi.Peer, ClusteredDOMDataTreeChangeListener, TransactionChainListener {
+public class ApplicationPeer extends BGPPeerStateImpl implements org.opendaylight.protocol.bgp.rib.spi.Peer,
+    ClusteredDOMDataTreeChangeListener, TransactionChainListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(ApplicationPeer.class);
 
@@ -249,8 +251,9 @@ public class ApplicationPeer extends BGPPeerStateImpl implements AutoCloseable,
         return this.name;
     }
 
+    // FIXME ListenableFuture<?> should be used once closeServiceInstance uses wildcard too
     @Override
-    public synchronized void close() {
+    public synchronized ListenableFuture<Void> close() {
         if (this.registration != null) {
             this.registration.close();
             this.registration = null;
@@ -258,8 +261,11 @@ public class ApplicationPeer extends BGPPeerStateImpl implements AutoCloseable,
         if (this.effectiveRibInWriter != null) {
             this.effectiveRibInWriter.close();
         }
+        final ListenableFuture<Void> future;
         if (this.adjRibInWriter != null) {
-            this.adjRibInWriter.removePeer();
+            future = this.adjRibInWriter.removePeer();
+        }else {
+            future = Futures.immediateFuture(null);
         }
         if (this.chain != null) {
             this.chain.close();
@@ -269,6 +275,7 @@ public class ApplicationPeer extends BGPPeerStateImpl implements AutoCloseable,
             this.writerChain.close();
             this.writerChain = null;
         }
+        return future;
     }
 
     @Override
index fd8205233f3e752be29e3b703e4c0617c5240496..0f6696b9145622f139bb615fac00cb1a34f6777a 100644 (file)
@@ -15,6 +15,8 @@ import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.net.InetAddresses;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -103,8 +105,8 @@ import org.slf4j.LoggerFactory;
  * Class representing a peer. We have a single instance for each peer, which provides translation from BGP events into
  * RIB actions.
  */
-public class BGPPeer extends BGPPeerStateImpl implements BGPSessionListener, Peer, AutoCloseable,
-    BGPPeerRuntimeMXBean, TransactionChainListener {
+public class BGPPeer extends BGPPeerStateImpl implements BGPSessionListener, Peer, BGPPeerRuntimeMXBean,
+    TransactionChainListener {
     private static final Logger LOG = LoggerFactory.getLogger(BGPPeer.class);
 
     @GuardedBy("this")
@@ -161,10 +163,12 @@ public class BGPPeer extends BGPPeerStateImpl implements BGPSessionListener, Pee
         this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.simpleRoutingPolicy, this.chain);
     }
 
+    // FIXME ListenableFuture<?> should be used once closeServiceInstance uses wildcard too
     @Override
-    public synchronized void close() {
-        releaseConnection();
+    public synchronized ListenableFuture<Void> close() {
+        final ListenableFuture<Void> future = releaseConnection();
         this.chain.close();
+        return future;
     }
 
     @Override
@@ -386,17 +390,18 @@ public class BGPPeer extends BGPPeerStateImpl implements BGPSessionListener, Pee
         }
     }
 
-    private void cleanup() {
+    private ListenableFuture<Void> cleanup() {
         // FIXME: BUG-196: support graceful
         this.adjRibOutListenerSet.values().forEach(AdjRibOutListener::close);
         this.adjRibOutListenerSet.clear();
         if (this.effRibInWriter != null) {
             this.effRibInWriter.close();
         }
-        if(this.ribWriter != null) {
-            this.ribWriter.removePeer();
-        }
         this.tables.clear();
+        if (this.ribWriter != null) {
+            return this.ribWriter.removePeer();
+        }
+        return Futures.immediateFuture(null);
     }
 
     @Override
@@ -432,15 +437,15 @@ public class BGPPeer extends BGPPeerStateImpl implements BGPSessionListener, Pee
     }
 
     @Override
-    @GuardedBy("this")
-    public synchronized void releaseConnection() {
+    public synchronized ListenableFuture<Void> releaseConnection() {
         if (this.rpcRegistration != null) {
             this.rpcRegistration.close();
         }
         closeRegistration();
-        cleanup();
+        final ListenableFuture<Void> future = cleanup();
         dropConnection();
         resetState();
+        return future;
     }
 
     private void closeRegistration() {
index 2a8ac86a8680373fce34cc77d6b58b0e9a477924..aea1d61336b311a2329ed19e4cb6cb555db5d1ae 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.protocol.bgp.rib.impl.config;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
-import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Objects;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -140,8 +139,7 @@ public final class AppPeer implements PeerBean, BGPPeerStateConsumer {
         @Override
         public ListenableFuture<Void> closeServiceInstance() {
             LOG.info("Application Peer Singleton Service {} instance closed", getIdentifier());
-            this.applicationPeer.close();
-            return Futures.immediateFuture(null);
+            return this.applicationPeer.close();
         }
 
         @Override
index dea2d865e28ba89aa4fbbc785f94c6ec49f7ebd9..ce2328217e6afa26e76f4b409a1e272ecc701847 100644 (file)
@@ -15,7 +15,6 @@ import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUti
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import io.netty.util.concurrent.Future;
 import java.net.InetSocketAddress;
@@ -36,7 +35,6 @@ import org.opendaylight.protocol.bgp.parser.BgpExtendedMessageUtil;
 import org.opendaylight.protocol.bgp.parser.spi.MultiprotocolCapabilitiesUtil;
 import org.opendaylight.protocol.bgp.rib.impl.BGPPeer;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
-import org.opendaylight.protocol.bgp.rib.impl.spi.BGPPeerRegistry;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPSessionPreferences;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer.WriteConfiguration;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
@@ -273,11 +271,11 @@ public final class BgpPeer implements PeerBean, BGPPeerStateConsumer, BGPPeerRun
                 this.connection.cancel(true);
                 this.connection = null;
             }
-            this.bgpPeer.close();
+            final ListenableFuture<Void> future = this.bgpPeer.close();
             if(BgpPeer.this.currentConfiguration != null) {
                 this.dispatcher.getBGPPeerRegistry().removePeer(BgpPeer.this.currentConfiguration.getNeighborAddress());
             }
-            return Futures.immediateFuture(null);
+            return future;
         }
 
         @Override
index 39167ebd39fc0d9f1775182b12171801b9f0e98a..aee98dc37a34a6c181bec2c5eb9737a92d6ef37d 100644 (file)
@@ -152,7 +152,7 @@ public class PeerTest extends AbstractRIBTestSetup {
         try {
             this.classic.onMessage(this.session, ub.build());
             fail();
-        } catch (BGPDocumentedException e) {
+        } catch (final BGPDocumentedException e) {
             assertEquals(BGPError.MANDATORY_ATTR_MISSING_MSG + "LOCAL_PREF", e.getMessage());
             assertEquals(BGPError.WELL_KNOWN_ATTR_MISSING.getCode(), e.getError().getCode());
             assertEquals(BGPError.WELL_KNOWN_ATTR_MISSING.getSubcode(), e.getError().getSubcode());
@@ -166,19 +166,18 @@ public class PeerTest extends AbstractRIBTestSetup {
         assertEquals(3, this.routes.size());
 
         //create new peer so that it gets advertized routes from RIB
-        try (final BGPPeer testingPeer = new BGPPeer(this.neighborAddress.getValue(), getRib(), PeerRole.Ibgp, null,
-            Collections.emptySet(), Collections.emptySet())) {
-            testingPeer.instantiateServiceInstance();
-            testingPeer.onSessionUp(this.session);
-            assertEquals(3, this.routes.size());
-            assertEquals(1, testingPeer.getBgpPeerState().getSessionEstablishedCount().getValue().intValue());
-            final List<RouteTable> routeTables = testingPeer.getBgpPeerState().getRouteTable();
-            assertEquals(1, routeTables.size());
-            final RouteTable routeTable = routeTables.get(0);
-            assertEquals(AFI_QNAME.toString(), routeTable.getAfi().getqNameOfIdentity());
-            assertEquals(SAFI_QNAME.toString(), routeTable.getSafi().getqNameOfIdentity());
-            assertNotNull(testingPeer.getBgpSessionState());
-        }
+        final BGPPeer testingPeer = new BGPPeer(this.neighborAddress.getValue(), getRib(), PeerRole.Ibgp, null,
+        Collections.emptySet(), Collections.emptySet());
+        testingPeer.instantiateServiceInstance();
+        testingPeer.onSessionUp(this.session);
+        assertEquals(3, this.routes.size());
+        assertEquals(1, testingPeer.getBgpPeerState().getSessionEstablishedCount().getValue().intValue());
+        final List<RouteTable> routeTables = testingPeer.getBgpPeerState().getRouteTable();
+        assertEquals(1, routeTables.size());
+        final RouteTable routeTable = routeTables.get(0);
+        assertEquals(AFI_QNAME.toString(), routeTable.getAfi().getqNameOfIdentity());
+        assertEquals(SAFI_QNAME.toString(), routeTable.getSafi().getqNameOfIdentity());
+        assertNotNull(testingPeer.getBgpSessionState());
 
         final List<Ipv4Prefix> prefs2 = Lists.newArrayList(new Ipv4Prefix("8.0.1.0/28"), new Ipv4Prefix("8.0.1.16/28"));
         ub.setNlri(new NlriBuilder().setNlri(prefs2).build());
index 1cc49d09e8d3fbc11d97ac40aab4d3c5f20a8527..8745da8ea6cdc51bb836434cfc092200a846598c 100644 (file)
@@ -8,6 +8,8 @@
 package org.opendaylight.protocol.bgp.rib.impl;
 
 import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.Uninterruptibles;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -71,7 +73,7 @@ public final class SimpleSessionListener implements BGPSessionListener, Listener
     }
 
     @Override
-    public void releaseConnection() {
+    public ListenableFuture<Void> releaseConnection() {
         LOG.debug("Releasing connection");
         if (this.session != null) {
             try {
@@ -80,6 +82,7 @@ public final class SimpleSessionListener implements BGPSessionListener, Listener
                 LOG.warn("Error closing session", e);
             }
         }
+        return Futures.immediateFuture(null);
     }
 
     public State getState() {
index 154b79770fbf27204d75f9e0ded1c71a4ce0a598..694952c2ebb05dbb58065ce54cfdf77dc2b024fc 100644 (file)
@@ -14,6 +14,7 @@ import static org.junit.Assert.fail;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
 import java.net.InetSocketAddress;
 import java.util.Collections;
 import java.util.List;
@@ -67,7 +68,7 @@ public class StrictBGPPeerRegistryTest {
 
     private static BGPSessionListener getMockSession() {
         final BGPSessionListener mock = Mockito.mock(BGPSessionListener.class);
-        Mockito.doNothing().when(mock).releaseConnection();
+        Mockito.doReturn(Futures.immediateFuture(null)).when(mock).releaseConnection();
         return mock;
     }
 
index be65fb4e24e60cb3fb08dc8673b6b6ec6f722396..4b30eee531cf9dd5fc1d061b7bd8ae184b473131 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.protocol.bgp.rib.spi;
 
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.EventListener;
 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
@@ -54,5 +55,5 @@ public interface BGPSessionListener extends EventListener {
      */
     void onMessage(BGPSession session, Notification notification) throws BGPDocumentedException;
 
-    void releaseConnection();
+    ListenableFuture<?> releaseConnection();
 }
index eb8ab087ad37df146009bf95d556030739e8b4ef..13ca868915b18ac7fdf732e351f92126564ae7f9 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.protocol.bgp.rib.spi;
 
+import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * Marker interface identifying a BGP peer.
@@ -24,4 +25,11 @@ public interface Peer {
      * @return byte[] raw identifier
      */
     byte[] getRawIdentifier();
+
+    /**
+     *  Close Peers and performs asynchronously DS clean up
+     *
+     * @return future
+     */
+    ListenableFuture<?> close();
 }
index 8ad753feb4bf993c359e25f4d2bcf69bf4626834..de2b7ffc90704cc5e4b7bea3d72ae9b20dbf18d1 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.protocol.bgp.testtool;
 
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.List;
 import java.util.concurrent.atomic.LongAdder;
 import org.opendaylight.protocol.bgp.rib.impl.BGPSessionImpl;
@@ -72,8 +74,9 @@ final class TestingListener implements BGPSessionListener {
     }
 
     @Override
-    public void releaseConnection() {
+    public ListenableFuture<?> releaseConnection() {
         LOG.info("Client Listener: Connection released.");
+        return Futures.immediateFuture(null);
     }
 
     void printCount(final String localAddress) {
index 1a7aaa821ff960b6dbd70abb2bba8b8967419c7d..63f4a9714adf4b1e364b48aafc56f7a653ce8200 100644 (file)
@@ -9,8 +9,10 @@ package org.opendaylight.bgpcep.bgp.topology.provider;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -41,15 +43,14 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public abstract class AbstractTopologyBuilder<T extends Route> implements AutoCloseable, ClusteredDataTreeChangeListener<T>, TopologyReference, TransactionChainListener {
+public abstract class AbstractTopologyBuilder<T extends Route> implements ClusteredDataTreeChangeListener<T>,
+    TopologyReference, TransactionChainListener {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractTopologyBuilder.class);
     // we limit the listener reset interval to be 5 min at most
     private static final long LISTENER_RESET_LIMIT_IN_MILLSEC = 5 * 60 * 1000;
@@ -147,17 +148,17 @@ public abstract class AbstractTopologyBuilder<T extends Route> implements AutoCl
         return this.topology;
     }
 
-    @Override
-    public final synchronized void close() {
+    public final synchronized ListenableFuture<Void> close() {
         if (this.closed) {
             LOG.trace("Transaction chain was already closed.");
-            return;
+            Futures.immediateFuture(null);
         }
         this.closed = true;
         LOG.info("Shutting down builder for {}", getInstanceIdentifier());
         unregisterDataChangeListener();
-        destroyOperationalTopology();
+        final ListenableFuture<Void> future = destroyOperationalTopology();
         destroyTransactionChain();
+        return future;
     }
 
     @Override
@@ -252,16 +253,25 @@ public abstract class AbstractTopologyBuilder<T extends Route> implements AutoCl
      * Destroy the current operational topology data. Note a valid transaction must be provided
      * @throws TransactionCommitFailedException
      */
-    private synchronized void destroyOperationalTopology() {
+    private synchronized ListenableFuture<Void> destroyOperationalTopology() {
         Preconditions.checkNotNull(this.chain, "A valid transaction chain must be provided.");
         final WriteTransaction trans = this.chain.newWriteOnlyTransaction();
         trans.delete(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier());
-        try {
-            trans.submit().checkedGet();
-        } catch (final TransactionCommitFailedException e) {
-            LOG.error("Unable to reset operational topology {} (transaction {})", this.topology, trans.getIdentifier(), e);
-        }
+        final CheckedFuture<Void, TransactionCommitFailedException> future = trans.submit();
+        Futures.addCallback(future, new FutureCallback<Void>() {
+            @Override
+            public void onSuccess(final Void result) {
+                LOG.trace("Operational topology removed {}", AbstractTopologyBuilder.this.topology);
+            }
+
+            @Override
+            public void onFailure(final Throwable t) {
+                LOG.error("Unable to reset operational topology {} (transaction {})",
+                    AbstractTopologyBuilder.this.topology, trans.getIdentifier(), t);
+            }
+        });
         clearTopology();
+        return future;
     }
 
     /**
index 655fd7705fd464bde83fd45caab8a371d2f819d5..fe4e35a9127b2922398e90b6b267d9c636bfa253 100644 (file)
@@ -59,8 +59,7 @@ final class TopologyReferenceSingletonServiceImpl implements TopologyReferenceSi
     @Override
     public ListenableFuture<Void> closeServiceInstance() {
         LOG.info("Close Topology Singleton Service {}", getIdentifier());
-        this.topologyBuilder.close();
-        return Futures.immediateFuture(null);
+        return this.topologyBuilder.close();
     }
 
     @Override