【问题标题】:Kotlin & Arrow.io: Transactions with IO.bracketCaseKotlin 和 Arrow.io:使用 IO.bracketCase 进行交易
【发布时间】:2019-03-12 18:51:51
【问题描述】:

我目前在 Kotlin 中使用 Arrow.io,我很想在工作项目中使用该库(与 Spring Boot 一起)。我不太清楚如何正确解决的一个问题是事务管理。 IO<A>.bracketCase(...) 在我看来是完成这项工作的正确工具。这是我目前正在研究的方法:

interface TransactionProvider {
    fun startTransaction(): IO<Transaction>
}

interface Transaction {
    fun commit(): IO<Unit>
    fun rollback(): IO<Unit>
}

fun <A> TransactionProvider.runInTransaction(action: IO<A>): IO<A> =
    startTransaction()
        .bracketCase(::releaseTransaction) { action }

fun releaseTransaction(t: Transaction, exitCase: ExitCase<Throwable>): IO<Unit> =
    when (exitCase) {
        is ExitCase.Completed -> t.commit()
        else -> t.rollback()
    }

遗憾的是,它并没有像我期望的那样工作:当在action 的执行过程中抛出异常时,我希望回滚。但事实并非如此(例如以下测试失败):

@Test
internal fun `transaction rolls back on failure`() {

    val transaction: Transaction =
        mock {
            on { commit() } doReturn IO.unit
            on { rollback() } doReturn IO.unit
        }

    val transactionProvider: TransactionProvider =
        mock{
            on { startTransaction() } doReturn IO.just(transaction)
        }

    val exception = IllegalArgumentException("Here I am!")
    val action = IO{ throw exception }


    val result: Either<Throwable, Unit> =
        transactionProvider
            .runInTransaction(action)
            .attempt()
            .unsafeRunSync()

    assertThat(result).isEqualTo(exception.left())

    verify(transaction, never()).commit()
    verify(transaction, times(1)).rollback()
}

我现在经常玩这个,无论我如何安排我的类型以及我将action 放在哪里有问题 - 我从来没有让bracketCase 回滚我的交易。我究竟做错了什么?有没有更好的方法来做到这一点?如果可能的话,我更喜欢不使用unsafeRun 的类型安全方式。

【问题讨论】:

    标签: kotlin functional-programming io-monad arrow-kt


    【解决方案1】:

    我认为除了测试代码之外,您的一切都是正确的——也许模拟与 IO 无法正常工作。例如,以下测试代码使用您在第一个 sn-p 中的 Transaction 定义按预期工作:

    fun main(args: Array<String>): Unit {
        val transactor = object: Transaction {
            override fun commit(): IO<Unit> = IO { println("Commit"); }
            override fun rollback(): IO<Unit> = IO { println("Rollback"); }
        }
    
        val txProvider = object: TransactionProvider {
            override fun startTransaction(): IO<Transaction> = IO.just(transactor)
        }
    
        val actionThrow = IO { println("Throwing"); throw IllegalArgumentException("Exception!") }
        val actionSuccess = IO { println("Returning value"); 2 }
    
        val resultThrow = txProvider.runInTransaction(actionThrow).attempt().unsafeRunSync()
        println(resultThrow)
        val resultSuccess = txProvider.runInTransaction(actionSuccess).attempt().unsafeRunSync()
        println(resultSuccess)
    }
    

    我得到的输出如下:

    Throwing
    Rollback
    Left(a=java.lang.IllegalArgumentException: Exception!)
    Returning value
    Commit
    Right(b=2)
    

    这正是我使用#bracketCase 所期望的。 (这是使用箭头 0.10.0-SNAPSHOT。)

    【讨论】:

      猜你喜欢
      • 2011-04-07
      • 1970-01-01
      • 1970-01-01
      • 2013-03-29
      • 1970-01-01
      • 1970-01-01
      • 2020-06-28
      • 2016-09-10
      • 2012-05-08
      相关资源
      最近更新 更多