From d97bc7dd1245ba7a06435e8b629f2c1b605fa3de Mon Sep 17 00:00:00 2001 From: Tamas Veingartner Date: Thu, 2 Jul 2020 11:35:04 +0100 Subject: [PATCH] ENT-5420 stop reconnecting when RejectedCommandException occurs. (#6394) * ENT-5420 stop reconnecting when RejectedCommandException occurs. * change to store last exception and return quietly * changed to rethrow exception. Test added --- .../CordaRPCClientReconnectionTest.kt | 33 +++++++++++++++++++ .../rpc/internal/ReconnectingCordaRPCOps.kt | 4 +-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect/CordaRPCClientReconnectionTest.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect/CordaRPCClientReconnectionTest.kt index 70ae13731f..fbf55e194b 100644 --- a/client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect/CordaRPCClientReconnectionTest.kt +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpcreconnect/CordaRPCClientReconnectionTest.kt @@ -15,6 +15,7 @@ import net.corda.finance.DOLLARS import net.corda.finance.contracts.asset.Cash import net.corda.finance.flows.CashIssueFlow import net.corda.node.services.Permissions +import net.corda.nodeapi.exceptions.RejectedCommandException import net.corda.testing.core.CHARLIE_NAME import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.NodeHandle @@ -49,6 +50,38 @@ class CordaRPCClientReconnectionTest { val rpcUser = User("user1", "test", permissions = setOf(Permissions.all())) } + + + + + @Test(timeout=300_000) + fun `rpc node start when FlowsDrainingModeEnabled throws RejectedCommandException and won't attempt to reconnect`() { + driver(DriverParameters(cordappsForAllNodes = FINANCE_CORDAPPS)) { + val address = NetworkHostAndPort("localhost", portAllocator.nextPort()) + + fun startNode(): NodeHandle { + return startNode( + providedName = CHARLIE_NAME, + rpcUsers = listOf(CordaRPCClientTest.rpcUser), + customOverrides = mapOf("rpcSettings.address" to address.toString()) + ).getOrThrow() + } + + val node = startNode() + val client = CordaRPCClient(node.rpcAddress, + config.copy(maxReconnectAttempts = 1)) + + (client.start(rpcUser.username, rpcUser.password, gracefulReconnect = gracefulReconnect)).use { + val rpcOps = it.proxy as ReconnectingCordaRPCOps + rpcOps.setFlowsDrainingModeEnabled(true) + + assertThatThrownBy { rpcOps.startTrackedFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0), defaultNotaryIdentity).returnValue.get() } + .isInstanceOf(RejectedCommandException::class.java).hasMessage("Node is draining before shutdown. Cannot start new flows through RPC.") + } + } + } + + @Test(timeout=300_000) fun `rpc client calls and returned observables continue working when the server crashes and restarts`() { driver(DriverParameters(cordappsForAllNodes = FINANCE_CORDAPPS)) { diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ReconnectingCordaRPCOps.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ReconnectingCordaRPCOps.kt index af3c7ab1b5..ff833dd03b 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ReconnectingCordaRPCOps.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/ReconnectingCordaRPCOps.kt @@ -325,8 +325,8 @@ class ReconnectingCordaRPCOps private constructor( } when (e.targetException) { is RejectedCommandException -> { - log.warn("Node is being shutdown. Operation ${method.name} rejected. Retrying when node is up...", e) - reconnectingRPCConnection.reconnectOnError(e) + log.warn("Node is being shutdown. Operation ${method.name} rejected. Shutting down...", e) + throw e.targetException } is ConnectionFailureException -> { log.warn("Failed to perform operation ${method.name}. Connection dropped. Retrying....", e)