mirror of
https://github.com/corda/corda.git
synced 2025-06-18 15:18:16 +00:00
Additional thread affinity for the StateMachineManager.
Check that the SMM.add method is being called on the SMM thread and throw if not. Make ServiceHubInternal.startFlow() do a blocking call onto the server thread. Update unit tests. This resolves an issue whereby the scheduler was starting flows outside of the server thread, which isn't intended.
This commit is contained in:
@ -58,6 +58,7 @@ interface ServiceHub {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the flow.
|
* Will check [logicType] and [args] against a whitelist and if acceptable then construct and initiate the flow.
|
||||||
|
* Note that you must be on the server thread to call this method.
|
||||||
*
|
*
|
||||||
* @throws IllegalFlowLogicException or IllegalArgumentException if there are problems with the [logicType] or [args].
|
* @throws IllegalFlowLogicException or IllegalArgumentException if there are problems with the [logicType] or [args].
|
||||||
*/
|
*/
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package net.corda.flows
|
package net.corda.flows
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import net.corda.testing.BOC
|
|
||||||
import net.corda.testing.BOC_KEY
|
|
||||||
import net.corda.flows.IssuerFlow.IssuanceRequester
|
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.contracts.DOLLARS
|
import net.corda.core.contracts.DOLLARS
|
||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
@ -14,10 +11,8 @@ import net.corda.core.serialization.OpaqueBytes
|
|||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY
|
import net.corda.core.utilities.DUMMY_NOTARY
|
||||||
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
import net.corda.core.utilities.DUMMY_NOTARY_KEY
|
||||||
import net.corda.testing.MEGA_CORP
|
import net.corda.flows.IssuerFlow.IssuanceRequester
|
||||||
import net.corda.testing.MEGA_CORP_KEY
|
import net.corda.testing.*
|
||||||
import net.corda.testing.initiateSingleShotFlow
|
|
||||||
import net.corda.testing.ledger
|
|
||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -62,7 +57,7 @@ class IssuerFlowTest {
|
|||||||
}.map { it.fsm }
|
}.map { it.fsm }
|
||||||
|
|
||||||
val issueRequest = IssuanceRequester(amount, issueToPartyAndRef.party, issueToPartyAndRef.reference, bankOfCordaNode.info.legalIdentity)
|
val issueRequest = IssuanceRequester(amount, issueToPartyAndRef.party, issueToPartyAndRef.reference, bankOfCordaNode.info.legalIdentity)
|
||||||
val issueRequestResultFuture = bankClientNode.smm.add(issueRequest).resultFuture
|
val issueRequestResultFuture = bankClientNode.services.startFlow(issueRequest).resultFuture
|
||||||
|
|
||||||
return IssuerFlowTest.RunResult(issuerFuture, issueRequestResultFuture)
|
return IssuerFlowTest.RunResult(issuerFuture, issueRequestResultFuture)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import com.google.common.util.concurrent.ListenableFuture
|
|||||||
import com.google.common.util.concurrent.MoreExecutors
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
import com.google.common.util.concurrent.SettableFuture
|
import com.google.common.util.concurrent.SettableFuture
|
||||||
import net.corda.core.*
|
import net.corda.core.*
|
||||||
import net.corda.core.contracts.Amount
|
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.X509Utilities
|
import net.corda.core.crypto.X509Utilities
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
@ -17,12 +16,14 @@ import net.corda.core.messaging.SingleMessageRecipient
|
|||||||
import net.corda.core.node.*
|
import net.corda.core.node.*
|
||||||
import net.corda.core.node.services.*
|
import net.corda.core.node.services.*
|
||||||
import net.corda.core.node.services.NetworkMapCache.MapChange
|
import net.corda.core.node.services.NetworkMapCache.MapChange
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.flows.*
|
import net.corda.flows.CashCommand
|
||||||
|
import net.corda.flows.CashFlow
|
||||||
|
import net.corda.flows.FinalityFlow
|
||||||
|
import net.corda.flows.sendRequest
|
||||||
import net.corda.node.api.APIServer
|
import net.corda.node.api.APIServer
|
||||||
import net.corda.node.services.api.*
|
import net.corda.node.services.api.*
|
||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
@ -123,7 +124,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, val netwo
|
|||||||
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
|
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
|
||||||
override val flowLogicRefFactory: FlowLogicRefFactory get() = flowLogicFactory
|
override val flowLogicRefFactory: FlowLogicRefFactory get() = flowLogicFactory
|
||||||
|
|
||||||
override fun <T> startFlow(logic: FlowLogic<T>): FlowStateMachine<T> = smm.add(logic)
|
override fun <T> startFlow(logic: FlowLogic<T>): FlowStateMachine<T> {
|
||||||
|
return serverThread.fetchFrom { smm.add(logic) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun registerFlowInitiator(markerClass: KClass<*>, flowFactory: (Party) -> FlowLogic<*>) {
|
override fun registerFlowInitiator(markerClass: KClass<*>, flowFactory: (Party) -> FlowLogic<*>) {
|
||||||
require(markerClass !in flowFactories) { "${markerClass.java.name} has already been used to register a flow" }
|
require(markerClass !in flowFactories) { "${markerClass.java.name} has already been used to register a flow" }
|
||||||
|
@ -64,9 +64,7 @@ abstract class ServiceHubInternal : PluginServiceHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: borrowing this method from service manager work in another branch. It's required to avoid circular dependency
|
* Starts an already constructed flow. Note that you must be on the server thread to call this method.
|
||||||
* between SMM and the scheduler. That particular problem should also be resolved by the service manager work
|
|
||||||
* itself, at which point this method would not be needed (by the scheduler).
|
|
||||||
*/
|
*/
|
||||||
abstract fun <T> startFlow(logic: FlowLogic<T>): FlowStateMachine<T>
|
abstract fun <T> startFlow(logic: FlowLogic<T>): FlowStateMachine<T>
|
||||||
|
|
||||||
|
@ -381,8 +381,11 @@ class StateMachineManager(val serviceHub: ServiceHubInternal,
|
|||||||
* Kicks off a brand new state machine of the given class.
|
* Kicks off a brand new state machine of the given class.
|
||||||
* The state machine will be persisted when it suspends, with automated restart if the StateMachineManager is
|
* The state machine will be persisted when it suspends, with automated restart if the StateMachineManager is
|
||||||
* restarted with checkpointed state machines in the storage service.
|
* restarted with checkpointed state machines in the storage service.
|
||||||
|
*
|
||||||
|
* Note that you must be on the [executor] thread.
|
||||||
*/
|
*/
|
||||||
fun <T> add(logic: FlowLogic<T>): FlowStateMachine<T> {
|
fun <T> add(logic: FlowLogic<T>): FlowStateMachine<T> {
|
||||||
|
executor.checkOnThread()
|
||||||
// We swap out the parent transaction context as using this frequently leads to a deadlock as we wait
|
// We swap out the parent transaction context as using this frequently leads to a deadlock as we wait
|
||||||
// on the flow completion future inside that context. The problem is that any progress checkpoints are
|
// on the flow completion future inside that context. The problem is that any progress checkpoints are
|
||||||
// unable to acquire the table lock and move forward till the calling transaction finishes.
|
// unable to acquire the table lock and move forward till the calling transaction finishes.
|
||||||
|
@ -59,7 +59,6 @@ import kotlin.test.assertTrue
|
|||||||
* We assume that Alice and Bob already found each other via some market, and have agreed the details already.
|
* We assume that Alice and Bob already found each other via some market, and have agreed the details already.
|
||||||
*/
|
*/
|
||||||
class TwoPartyTradeFlowTests {
|
class TwoPartyTradeFlowTests {
|
||||||
|
|
||||||
lateinit var net: MockNetwork
|
lateinit var net: MockNetwork
|
||||||
lateinit var notaryNode: MockNetwork.MockNode
|
lateinit var notaryNode: MockNetwork.MockNode
|
||||||
lateinit var aliceNode: MockNetwork.MockNode
|
lateinit var aliceNode: MockNetwork.MockNode
|
||||||
@ -418,7 +417,7 @@ class TwoPartyTradeFlowTests {
|
|||||||
Buyer(otherParty, notaryNode.info.notaryIdentity, 1000.DOLLARS, CommercialPaper.State::class.java)
|
Buyer(otherParty, notaryNode.info.notaryIdentity, 1000.DOLLARS, CommercialPaper.State::class.java)
|
||||||
}.map { it.fsm }
|
}.map { it.fsm }
|
||||||
val seller = Seller(bobNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, ALICE_KEY)
|
val seller = Seller(bobNode.info.legalIdentity, notaryNode.info, assetToSell, 1000.DOLLARS, ALICE_KEY)
|
||||||
val sellerResultFuture = aliceNode.smm.add(seller).resultFuture
|
val sellerResultFuture = aliceNode.services.startFlow(seller).resultFuture
|
||||||
return RunResult(buyerFuture, sellerResultFuture, seller.fsm.id)
|
return RunResult(buyerFuture, sellerResultFuture, seller.fsm.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,9 @@ open class MockServiceHubInternal(
|
|||||||
|
|
||||||
override fun recordTransactions(txs: Iterable<SignedTransaction>) = recordTransactionsInternal(txStorageService, txs)
|
override fun recordTransactions(txs: Iterable<SignedTransaction>) = recordTransactionsInternal(txStorageService, txs)
|
||||||
|
|
||||||
override fun <T> startFlow(logic: FlowLogic<T>): FlowStateMachine<T> = smm.add(logic)
|
override fun <T> startFlow(logic: FlowLogic<T>): FlowStateMachine<T> {
|
||||||
|
return smm.executor.fetchFrom { smm.add(logic) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun registerFlowInitiator(markerClass: KClass<*>, flowFactory: (Party) -> FlowLogic<*>) {
|
override fun registerFlowInitiator(markerClass: KClass<*>, flowFactory: (Party) -> FlowLogic<*>) {
|
||||||
flowFactories[markerClass.java] = flowFactory
|
flowFactories[markerClass.java] = flowFactory
|
||||||
|
@ -38,7 +38,6 @@ import java.util.concurrent.TimeUnit
|
|||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
|
||||||
|
|
||||||
val realClock: Clock = Clock.systemUTC()
|
val realClock: Clock = Clock.systemUTC()
|
||||||
val stoppedClock = Clock.fixed(realClock.instant(), realClock.zone)
|
val stoppedClock = Clock.fixed(realClock.instant(), realClock.zone)
|
||||||
val testClock = TestClock(stoppedClock)
|
val testClock = TestClock(stoppedClock)
|
||||||
|
@ -39,7 +39,6 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class StateMachineManagerTests {
|
class StateMachineManagerTests {
|
||||||
|
|
||||||
private val net = MockNetwork(servicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin())
|
private val net = MockNetwork(servicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin())
|
||||||
private val sessionTransfers = ArrayList<SessionTransfer>()
|
private val sessionTransfers = ArrayList<SessionTransfer>()
|
||||||
private lateinit var node1: MockNode
|
private lateinit var node1: MockNode
|
||||||
@ -69,7 +68,7 @@ class StateMachineManagerTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `newly added flow is preserved on restart`() {
|
fun `newly added flow is preserved on restart`() {
|
||||||
node1.smm.add(NoOpFlow(nonTerminating = true))
|
node1.services.startFlow(NoOpFlow(nonTerminating = true))
|
||||||
node1.acceptableLiveFiberCountOnStop = 1
|
node1.acceptableLiveFiberCountOnStop = 1
|
||||||
val restoredFlow = node1.restartAndGetRestoredFlow<NoOpFlow>()
|
val restoredFlow = node1.restartAndGetRestoredFlow<NoOpFlow>()
|
||||||
assertThat(restoredFlow.flowStarted).isTrue()
|
assertThat(restoredFlow.flowStarted).isTrue()
|
||||||
@ -82,7 +81,7 @@ class StateMachineManagerTests {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call() = Unit
|
override fun call() = Unit
|
||||||
}
|
}
|
||||||
node1.smm.add(flow)
|
node1.services.startFlow(flow)
|
||||||
assertThat(flow.lazyTime).isNotNull()
|
assertThat(flow.lazyTime).isNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +89,7 @@ class StateMachineManagerTests {
|
|||||||
fun `flow restarted just after receiving payload`() {
|
fun `flow restarted just after receiving payload`() {
|
||||||
node2.services.registerFlowInitiator(SendFlow::class) { ReceiveThenSuspendFlow(it) }
|
node2.services.registerFlowInitiator(SendFlow::class) { ReceiveThenSuspendFlow(it) }
|
||||||
val payload = random63BitValue()
|
val payload = random63BitValue()
|
||||||
node1.smm.add(SendFlow(payload, node2.info.legalIdentity))
|
node1.services.startFlow(SendFlow(payload, node2.info.legalIdentity))
|
||||||
|
|
||||||
// We push through just enough messages to get only the payload sent
|
// We push through just enough messages to get only the payload sent
|
||||||
node2.pumpReceive()
|
node2.pumpReceive()
|
||||||
@ -106,7 +105,7 @@ class StateMachineManagerTests {
|
|||||||
fun `flow added before network map does run after init`() {
|
fun `flow added before network map does run after init`() {
|
||||||
val node3 = net.createNode(node1.info.address) //create vanilla node
|
val node3 = net.createNode(node1.info.address) //create vanilla node
|
||||||
val flow = NoOpFlow()
|
val flow = NoOpFlow()
|
||||||
node3.smm.add(flow)
|
node3.services.startFlow(flow)
|
||||||
assertEquals(false, flow.flowStarted) // Not started yet as no network activity has been allowed yet
|
assertEquals(false, flow.flowStarted) // Not started yet as no network activity has been allowed yet
|
||||||
net.runNetwork() // Allow network map messages to flow
|
net.runNetwork() // Allow network map messages to flow
|
||||||
assertEquals(true, flow.flowStarted) // Now we should have run the flow
|
assertEquals(true, flow.flowStarted) // Now we should have run the flow
|
||||||
@ -116,7 +115,7 @@ class StateMachineManagerTests {
|
|||||||
fun `flow added before network map will be init checkpointed`() {
|
fun `flow added before network map will be init checkpointed`() {
|
||||||
var node3 = net.createNode(node1.info.address) //create vanilla node
|
var node3 = net.createNode(node1.info.address) //create vanilla node
|
||||||
val flow = NoOpFlow()
|
val flow = NoOpFlow()
|
||||||
node3.smm.add(flow)
|
node3.services.startFlow(flow)
|
||||||
assertEquals(false, flow.flowStarted) // Not started yet as no network activity has been allowed yet
|
assertEquals(false, flow.flowStarted) // Not started yet as no network activity has been allowed yet
|
||||||
node3.disableDBCloseOnStop()
|
node3.disableDBCloseOnStop()
|
||||||
node3.stop()
|
node3.stop()
|
||||||
@ -141,7 +140,7 @@ class StateMachineManagerTests {
|
|||||||
fun `flow loaded from checkpoint will respond to messages from before start`() {
|
fun `flow loaded from checkpoint will respond to messages from before start`() {
|
||||||
val payload = random63BitValue()
|
val payload = random63BitValue()
|
||||||
node1.services.registerFlowInitiator(ReceiveThenSuspendFlow::class) { SendFlow(payload, it) }
|
node1.services.registerFlowInitiator(ReceiveThenSuspendFlow::class) { SendFlow(payload, it) }
|
||||||
node2.smm.add(ReceiveThenSuspendFlow(node1.info.legalIdentity)) // Prepare checkpointed receive flow
|
node2.services.startFlow(ReceiveThenSuspendFlow(node1.info.legalIdentity)) // Prepare checkpointed receive flow
|
||||||
// Make sure the add() has finished initial processing.
|
// Make sure the add() has finished initial processing.
|
||||||
node2.smm.executor.flush()
|
node2.smm.executor.flush()
|
||||||
node2.disableDBCloseOnStop()
|
node2.disableDBCloseOnStop()
|
||||||
@ -163,7 +162,7 @@ class StateMachineManagerTests {
|
|||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
|
|
||||||
// Kick off first send and receive
|
// Kick off first send and receive
|
||||||
node2.smm.add(PingPongFlow(node3.info.legalIdentity, payload))
|
node2.services.startFlow(PingPongFlow(node3.info.legalIdentity, payload))
|
||||||
databaseTransaction(node2.database) {
|
databaseTransaction(node2.database) {
|
||||||
assertEquals(1, node2.checkpointStorage.checkpoints().size)
|
assertEquals(1, node2.checkpointStorage.checkpoints().size)
|
||||||
}
|
}
|
||||||
@ -207,7 +206,7 @@ class StateMachineManagerTests {
|
|||||||
node2.services.registerFlowInitiator(SendFlow::class) { ReceiveThenSuspendFlow(it) }
|
node2.services.registerFlowInitiator(SendFlow::class) { ReceiveThenSuspendFlow(it) }
|
||||||
node3.services.registerFlowInitiator(SendFlow::class) { ReceiveThenSuspendFlow(it) }
|
node3.services.registerFlowInitiator(SendFlow::class) { ReceiveThenSuspendFlow(it) }
|
||||||
val payload = random63BitValue()
|
val payload = random63BitValue()
|
||||||
node1.smm.add(SendFlow(payload, node2.info.legalIdentity, node3.info.legalIdentity))
|
node1.services.startFlow(SendFlow(payload, node2.info.legalIdentity, node3.info.legalIdentity))
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
val node2Flow = node2.getSingleFlow<ReceiveThenSuspendFlow>().first
|
val node2Flow = node2.getSingleFlow<ReceiveThenSuspendFlow>().first
|
||||||
val node3Flow = node3.getSingleFlow<ReceiveThenSuspendFlow>().first
|
val node3Flow = node3.getSingleFlow<ReceiveThenSuspendFlow>().first
|
||||||
@ -241,7 +240,7 @@ class StateMachineManagerTests {
|
|||||||
node2.services.registerFlowInitiator(ReceiveThenSuspendFlow::class) { SendFlow(node2Payload, it) }
|
node2.services.registerFlowInitiator(ReceiveThenSuspendFlow::class) { SendFlow(node2Payload, it) }
|
||||||
node3.services.registerFlowInitiator(ReceiveThenSuspendFlow::class) { SendFlow(node3Payload, it) }
|
node3.services.registerFlowInitiator(ReceiveThenSuspendFlow::class) { SendFlow(node3Payload, it) }
|
||||||
val multiReceiveFlow = ReceiveThenSuspendFlow(node2.info.legalIdentity, node3.info.legalIdentity)
|
val multiReceiveFlow = ReceiveThenSuspendFlow(node2.info.legalIdentity, node3.info.legalIdentity)
|
||||||
node1.smm.add(multiReceiveFlow)
|
node1.services.startFlow(multiReceiveFlow)
|
||||||
node1.acceptableLiveFiberCountOnStop = 1
|
node1.acceptableLiveFiberCountOnStop = 1
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
assertThat(multiReceiveFlow.receivedPayloads[0]).isEqualTo(node2Payload)
|
assertThat(multiReceiveFlow.receivedPayloads[0]).isEqualTo(node2Payload)
|
||||||
@ -265,7 +264,7 @@ class StateMachineManagerTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `both sides do a send as their first IO request`() {
|
fun `both sides do a send as their first IO request`() {
|
||||||
node2.services.registerFlowInitiator(PingPongFlow::class) { PingPongFlow(it, 20L) }
|
node2.services.registerFlowInitiator(PingPongFlow::class) { PingPongFlow(it, 20L) }
|
||||||
node1.smm.add(PingPongFlow(node2.info.legalIdentity, 10L))
|
node1.services.startFlow(PingPongFlow(node2.info.legalIdentity, 10L))
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
|
|
||||||
assertSessionTransfers(
|
assertSessionTransfers(
|
||||||
@ -332,7 +331,7 @@ class StateMachineManagerTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `exception thrown on other side`() {
|
fun `exception thrown on other side`() {
|
||||||
node2.services.registerFlowInitiator(ReceiveThenSuspendFlow::class) { ExceptionFlow }
|
node2.services.registerFlowInitiator(ReceiveThenSuspendFlow::class) { ExceptionFlow }
|
||||||
val future = node1.smm.add(ReceiveThenSuspendFlow(node2.info.legalIdentity)).resultFuture
|
val future = node1.services.startFlow(ReceiveThenSuspendFlow(node2.info.legalIdentity)).resultFuture
|
||||||
net.runNetwork()
|
net.runNetwork()
|
||||||
assertThatThrownBy { future.getOrThrow() }.isInstanceOf(FlowSessionException::class.java)
|
assertThatThrownBy { future.getOrThrow() }.isInstanceOf(FlowSessionException::class.java)
|
||||||
assertSessionTransfers(
|
assertSessionTransfers(
|
||||||
@ -413,7 +412,6 @@ class StateMachineManagerTests {
|
|||||||
|
|
||||||
|
|
||||||
private class NoOpFlow(val nonTerminating: Boolean = false) : FlowLogic<Unit>() {
|
private class NoOpFlow(val nonTerminating: Boolean = false) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
@Transient var flowStarted = false
|
@Transient var flowStarted = false
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
@ -427,7 +425,6 @@ class StateMachineManagerTests {
|
|||||||
|
|
||||||
|
|
||||||
private class SendFlow(val payload: Any, vararg val otherParties: Party) : FlowLogic<Unit>() {
|
private class SendFlow(val payload: Any, vararg val otherParties: Party) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(otherParties.isNotEmpty())
|
require(otherParties.isNotEmpty())
|
||||||
}
|
}
|
||||||
@ -438,7 +435,6 @@ class StateMachineManagerTests {
|
|||||||
|
|
||||||
|
|
||||||
private class ReceiveThenSuspendFlow(vararg val otherParties: Party) : FlowLogic<Unit>() {
|
private class ReceiveThenSuspendFlow(vararg val otherParties: Party) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
require(otherParties.isNotEmpty())
|
require(otherParties.isNotEmpty())
|
||||||
}
|
}
|
||||||
@ -453,7 +449,6 @@ class StateMachineManagerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class PingPongFlow(val otherParty: Party, val payload: Long) : FlowLogic<Unit>() {
|
private class PingPongFlow(val otherParty: Party, val payload: Long) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
@Transient var receivedPayload: Long? = null
|
@Transient var receivedPayload: Long? = null
|
||||||
@Transient var receivedPayload2: Long? = null
|
@Transient var receivedPayload2: Long? = null
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user