mirror of
https://github.com/corda/corda.git
synced 2025-06-12 20:28:18 +00:00
CORDA-1475 CORDA-1465 Allow flows to retry from last checkpoint (#3204)
This commit is contained in:
@ -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.
|
||||
|
@ -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() }
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user