mirror of
https://github.com/corda/corda.git
synced 2025-04-27 14:29:52 +00:00
[CORDA-2265]: Nodes hangs when using AppServiceHub to start a flow in a blocking way (fix) (#4376)
This commit is contained in:
parent
c46fde1133
commit
e2ea97bae7
@ -28,6 +28,8 @@ Unreleased
|
||||
|
||||
* Improved exception thrown by `AttachmentsClassLoader` when an attachment cannot be used because its uploader is not trusted.
|
||||
|
||||
* Fixed deadlocks generated by starting flow from within CordaServices.
|
||||
|
||||
* Marked the ``Attachment`` interface as ``@DoNotImplement`` because it is not meant to be extended by CorDapp developers. If you have already
|
||||
done so, please get in contact on the usual communication channels.
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
package net.corda.node.services
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.flows.StartableByService
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.node.AppServiceHub
|
||||
import net.corda.core.node.services.CordaService
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.driver
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class CordaServiceFlowTests {
|
||||
@Test
|
||||
fun `corda service can start a flow and wait for it`() {
|
||||
driver(DriverParameters(startNodesInProcess = true)) {
|
||||
val node = startNode().getOrThrow()
|
||||
val text = "191ejodaimadc8i"
|
||||
|
||||
val length = node.rpc.startFlow(::ComputeTextLengthThroughCordaService, text).returnValue.getOrThrow()
|
||||
|
||||
assertThat(length).isEqualTo(text.length)
|
||||
}
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
class ComputeTextLengthThroughCordaService(private val text: String) : FlowLogic<Int>() {
|
||||
@Suspendable
|
||||
override fun call(): Int {
|
||||
val service = serviceHub.cordaService(TextLengthComputingService::class.java)
|
||||
return service.computeLength(text)
|
||||
}
|
||||
}
|
||||
|
||||
@StartableByService
|
||||
class ActuallyComputeTextLength(private val text: String) : FlowLogic<Int>() {
|
||||
@Suspendable
|
||||
override fun call(): Int {
|
||||
return text.length
|
||||
}
|
||||
}
|
||||
|
||||
@CordaService
|
||||
class TextLengthComputingService(private val services: AppServiceHub) : SingletonSerializeAsToken() {
|
||||
fun computeLength(text: String): Int {
|
||||
// Just to check this works with Quasar.
|
||||
require(text.isNotEmpty()) { "Length must be at least 1." }
|
||||
return services.startFlow(ActuallyComputeTextLength(text)).returnValue.toCompletableFuture().getOrThrow()
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.internal.concurrent.doneFuture
|
||||
import net.corda.core.internal.concurrent.map
|
||||
import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.internal.notary.NotaryService
|
||||
@ -601,8 +602,16 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
}
|
||||
|
||||
override fun <T> startFlow(flow: FlowLogic<T>): FlowHandle<T> {
|
||||
val stateMachine = startFlowChecked(flow)
|
||||
return FlowHandleImpl(id = stateMachine.id, returnValue = stateMachine.resultFuture)
|
||||
val parentFlow = FlowLogic.currentTopLevel
|
||||
return if (parentFlow != null) {
|
||||
val result = parentFlow.subFlow(flow)
|
||||
// Accessing the flow id must happen after the flow has started.
|
||||
val flowId = flow.runId
|
||||
FlowHandleImpl(flowId, doneFuture(result))
|
||||
} else {
|
||||
val stateMachine = startFlowChecked(flow)
|
||||
FlowHandleImpl(id = stateMachine.id, returnValue = stateMachine.resultFuture)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> startFlowChecked(flow: FlowLogic<T>): FlowStateMachine<T> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user