Kotlin & Arrow.io: транзакции с IO.bracketCase - PullRequest
1 голос
/ 12 марта 2019

В настоящее время я играю с 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, если это вообще возможно.

...