mirror of
https://github.com/corda/corda.git
synced 2024-12-19 13:08:04 +00:00
Flows shouldn't have to suspend if just doing a send (#187)
* CORDA-45 Flows shouldn't have to suspend if just doing a send
This commit is contained in:
parent
e383752995
commit
e8015e689a
@ -89,7 +89,10 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
||||
_resultFuture?.setException(t)
|
||||
throw ExecutionException(t)
|
||||
}
|
||||
|
||||
// Wait for sessions with unconfirmed session state.
|
||||
openSessions.values.filter { it.state is FlowSessionState.Initiating }.forEach {
|
||||
it.waitForConfirmation()
|
||||
}
|
||||
// This is to prevent actionOnEnd being called twice if it throws an exception
|
||||
actionOnEnd()
|
||||
_resultFuture?.set(result)
|
||||
@ -121,34 +124,48 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
||||
otherParty: Party,
|
||||
payload: Any,
|
||||
sessionFlow: FlowLogic<*>): UntrustworthyData<T> {
|
||||
val (session, new) = getSession(otherParty, sessionFlow, payload)
|
||||
val receivedSessionData = if (new) {
|
||||
val session = getConfirmedSession(otherParty, sessionFlow)
|
||||
return if (session == null) {
|
||||
// Only do a receive here as the session init has carried the payload
|
||||
receiveInternal<SessionData>(session)
|
||||
receiveInternal<SessionData>(startNewSession(otherParty, sessionFlow, payload, waitForConfirmation = true))
|
||||
} else {
|
||||
val sendSessionData = createSessionData(session, payload)
|
||||
sendAndReceiveInternal<SessionData>(session, sendSessionData)
|
||||
}
|
||||
return receivedSessionData.checkPayloadIs(receiveType)
|
||||
sendAndReceiveInternal<SessionData>(session, createSessionData(session, payload))
|
||||
}.checkPayloadIs(receiveType)
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
override fun <T : Any> receive(receiveType: Class<T>,
|
||||
otherParty: Party,
|
||||
sessionFlow: FlowLogic<*>): UntrustworthyData<T> {
|
||||
val session = getSession(otherParty, sessionFlow, null).first
|
||||
val session = getConfirmedSession(otherParty, sessionFlow) ?: startNewSession(otherParty, sessionFlow, null, waitForConfirmation = true)
|
||||
return receiveInternal<SessionData>(session).checkPayloadIs(receiveType)
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
override fun send(otherParty: Party, payload: Any, sessionFlow: FlowLogic<*>) {
|
||||
val (session, new) = getSession(otherParty, sessionFlow, payload)
|
||||
if (!new) {
|
||||
val session = getConfirmedSession(otherParty, sessionFlow)
|
||||
if (session == null) {
|
||||
// Don't send the payload again if it was already piggy-backed on a session init
|
||||
startNewSession(otherParty, sessionFlow, payload, waitForConfirmation = false)
|
||||
} else {
|
||||
sendInternal(session, createSessionData(session, payload))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will suspend the state machine and wait for incoming session init response from other party.
|
||||
*/
|
||||
@Suspendable
|
||||
private fun FlowSession.waitForConfirmation() {
|
||||
val (peerParty, sessionInitResponse) = receiveInternal<SessionInitResponse>(this)
|
||||
if (sessionInitResponse is SessionConfirm) {
|
||||
state = FlowSessionState.Initiated(peerParty, sessionInitResponse.initiatedSessionId)
|
||||
} else {
|
||||
sessionInitResponse as SessionReject
|
||||
throw FlowException("Party ${state.sendToParty} rejected session request: ${sessionInitResponse.errorMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSessionData(session: FlowSession, payload: Any): SessionData {
|
||||
val sessionState = session.state
|
||||
val peerSessionId = when (sessionState) {
|
||||
@ -174,12 +191,12 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
private fun getSession(otherParty: Party, sessionFlow: FlowLogic<*>, firstPayload: Any?): Pair<FlowSession, Boolean> {
|
||||
val session = openSessions[Pair(sessionFlow, otherParty)]
|
||||
return if (session != null) {
|
||||
Pair(session, false)
|
||||
} else {
|
||||
Pair(startNewSession(otherParty, sessionFlow, firstPayload), true)
|
||||
private fun getConfirmedSession(otherParty: Party, sessionFlow: FlowLogic<*>): FlowSession? {
|
||||
return openSessions[Pair(sessionFlow, otherParty)]?.apply {
|
||||
if (state is FlowSessionState.Initiating) {
|
||||
// Session still initiating, try to retrieve the init response.
|
||||
waitForConfirmation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,21 +207,17 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
||||
* multiple public keys, but we **don't support multiple nodes advertising the same legal identity**.
|
||||
*/
|
||||
@Suspendable
|
||||
private fun startNewSession(otherParty: Party, sessionFlow: FlowLogic<*>, firstPayload: Any?): FlowSession {
|
||||
private fun startNewSession(otherParty: Party, sessionFlow: FlowLogic<*>, firstPayload: Any?, waitForConfirmation: Boolean): FlowSession {
|
||||
logger.trace { "Initiating a new session with $otherParty" }
|
||||
val session = FlowSession(sessionFlow, random63BitValue(), FlowSessionState.Initiating(otherParty))
|
||||
openSessions[Pair(sessionFlow, otherParty)] = session
|
||||
val counterpartyFlow = sessionFlow.getCounterpartyMarker(otherParty).name
|
||||
val sessionInit = SessionInit(session.ourSessionId, counterpartyFlow, firstPayload)
|
||||
val (peerParty, sessionInitResponse) = sendAndReceiveInternal<SessionInitResponse>(session, sessionInit)
|
||||
if (sessionInitResponse is SessionConfirm) {
|
||||
require(session.state is FlowSessionState.Initiating)
|
||||
session.state = FlowSessionState.Initiated(peerParty, sessionInitResponse.initiatedSessionId)
|
||||
return session
|
||||
} else {
|
||||
sessionInitResponse as SessionReject
|
||||
throw FlowException("Party $otherParty rejected session request: ${sessionInitResponse.errorMessage}")
|
||||
sendInternal(session, sessionInit)
|
||||
if (waitForConfirmation) {
|
||||
session.waitForConfirmation()
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
@Suspendable
|
||||
|
Loading…
Reference in New Issue
Block a user