CORDA-1475 CORDA-1465 Allow flows to retry from last checkpoint (#3204)

This commit is contained in:
Rick Parker
2018-05-25 13:26:00 +01:00
committed by GitHub
parent 7cbc316b9d
commit 59fdb3df67
41 changed files with 1843 additions and 469 deletions

View File

@ -5,7 +5,6 @@ import net.corda.core.schemas.MappedSchema
import net.corda.core.utilities.contextLogger
import rx.Observable
import rx.Subscriber
import rx.subjects.PublishSubject
import rx.subjects.UnicastSubject
import java.io.Closeable
import java.sql.Connection
@ -67,9 +66,7 @@ class CordaPersistence(
}
val entityManagerFactory get() = hibernateConfig.sessionFactoryForRegisteredSchemas
data class Boundary(val txId: UUID)
internal val transactionBoundaries = PublishSubject.create<Boundary>().toSerialized()
data class Boundary(val txId: UUID, val success: Boolean)
init {
// Found a unit test that was forgetting to close the database transactions. When you close() on the top level
@ -186,15 +183,19 @@ class CordaPersistence(
*
* For examples, see the call hierarchy of this function.
*/
fun <T : Any> rx.Observer<T>.bufferUntilDatabaseCommit(): rx.Observer<T> {
val currentTxId = contextTransaction.id
val databaseTxBoundary: Observable<CordaPersistence.Boundary> = contextDatabase.transactionBoundaries.first { it.txId == currentTxId }
fun <T : Any> rx.Observer<T>.bufferUntilDatabaseCommit(propagateRollbackAsError: Boolean = false): rx.Observer<T> {
val currentTx = contextTransaction
val subject = UnicastSubject.create<T>()
val databaseTxBoundary: Observable<CordaPersistence.Boundary> = currentTx.boundary.filter { it.success }
if (propagateRollbackAsError) {
currentTx.boundary.filter { !it.success }.subscribe { this.onError(DatabaseTransactionRolledBackException(it.txId)) }
}
subject.delaySubscription(databaseTxBoundary).subscribe(this)
databaseTxBoundary.doOnCompleted { subject.onCompleted() }
return subject
}
class DatabaseTransactionRolledBackException(txId: UUID) : Exception("Database transaction $txId was rolled back")
// A subscriber that delegates to multiple others, wrapping a database transaction around the combination.
private class DatabaseTransactionWrappingSubscriber<U>(private val db: CordaPersistence?) : Subscriber<U>() {
// Some unsubscribes happen inside onNext() so need something that supports concurrent modification.

View File

@ -3,6 +3,7 @@ package net.corda.nodeapi.internal.persistence
import co.paralleluniverse.strands.Strand
import org.hibernate.Session
import org.hibernate.Transaction
import rx.subjects.PublishSubject
import java.sql.Connection
import java.util.*
@ -35,11 +36,16 @@ class DatabaseTransaction(
val session: Session by sessionDelegate
private lateinit var hibernateTransaction: Transaction
internal val boundary = PublishSubject.create<CordaPersistence.Boundary>()
private var committed = false
fun commit() {
if (sessionDelegate.isInitialized()) {
hibernateTransaction.commit()
}
connection.commit()
committed = true
}
fun rollback() {
@ -58,7 +64,15 @@ class DatabaseTransaction(
connection.close()
contextTransactionOrNull = outerTransaction
if (outerTransaction == null) {
database.transactionBoundaries.onNext(CordaPersistence.Boundary(id))
boundary.onNext(CordaPersistence.Boundary(id, committed))
}
}
fun onCommit(callback: () -> Unit) {
boundary.filter { it.success }.subscribe { callback() }
}
fun onRollback(callback: () -> Unit) {
boundary.filter { !it.success }.subscribe { callback() }
}
}