Hi, i’m trying to update a column in a database ev...
# arrow
j
Hi, i’m trying to update a column in a database everytime there is an exception but cannto figure out how to do it. I’m using ktor + exposed + arrow. Below is part of the code. Not sure if there is a better way to handle it.
Copy code
post {
var externalKeyValue = null
effect{
     val keyValue = requestHeaderCaching<String>(IDEMPOTENCY_KEY_HEADER).bind()
     externalKeyValue = keyValue
    newSuspendeTransaction {
       idempotencyKeyService.insertRecord(record).bind()
    }
}.fold(
    {
        println("Handle exception thrown by the code")
        if (externalKeyValue != null) {
            newSuspendedTransaction {
                idempotencyKeyService.unlockKey(idempotencyKey = externalKeyValue!!).bind() //CANNOT BIND HERE!!
            }
        }
        throw it
    },
    {
        println("BUSINESS ERROR")
        handleLeft(it)
    },
    {
        call.respond(HttpStatusCode.Created)
    }
)
}
s
You can lift the
exception
handler into the
effect
as well.
Copy code
post {
var externalKeyValue = null
effect{
    val keyValue = requestHeaderCaching<String>(IDEMPOTENCY_KEY_HEADER).bind()
    externalKeyValue = keyValue
    catch({
      newSuspendeTransaction {
         idempotencyKeyService.insertRecord(record).bind()
      }
    )} { 
        println("Handle exception thrown by the code")
        if (externalKeyValue != null) {
            newSuspendedTransaction {
                idempotencyKeyService.unlockKey(idempotencyKey = externalKeyValue!!).bind()
            }
        }
        throw it
    }
}.fold(
    {
        println("BUSINESS ERROR")
        handleLeft(it)
    },
    {
        call.respond(HttpStatusCode.Created)
    }
)
}
You can also write:
Copy code
post {
var externalKeyValue = null
recover({
    val keyValue = requestHeaderCaching<String>(IDEMPOTENCY_KEY_HEADER).bind()
    externalKeyValue = keyValue
    catch({
      newSuspendeTransaction {
         idempotencyKeyService.insertRecord(record).bind()
      }
    )} { 
        println("Handle exception thrown by the code")
        if (externalKeyValue != null) {
            newSuspendedTransaction {
                idempotencyKeyService.unlockKey(idempotencyKey = externalKeyValue!!).bind()
            }
        }
        throw it
    }
    call.respond(HttpStatusCode.Created)
}) {
  println("BUSINESS ERROR")
  handleLeft(it)
}
}
Hope that helps Jorge, be sure to ask any questions if anything is unclear ☺️
j
Nice, I'll give a try, thanks once again, Simon
Hi, i was trying the approach with catch, however, when execution thread enters
.mapLeft
i lost control there, i don`t know what is happening but neither the transaction nor the exception are executed.
Copy code
effect {
            when (currentKey.recoveryPoint) {
                STARTED -> {
                    catch {
                        newSuspendedTransaction {
                            addLogger(StdOutSqlLogger)
                            throw IllegalStateException()
                        }
                    }.mapLeft {
                        newSuspendedTransaction {
                            // we don't know what happened with the request. Let's unlock the row for retry.
                            idempotencyKeyService.updateKey(currentKey.copy(lockedAt = null)).bind()
                        }
                        throw it
                    }
                }
                else -> {}
            }
        }
    }
        .fold(
            {
                println("CAN RETRY")
                throw it
            },
            {
                println("FINISHED WITH ERROR")
                handleLeft(it)
            },
            {
                println("FINISHED WITH OK")
                call.respond(HttpStatusCode.Created)
            }
        )
}
seems that setting a diffrent context makes it work, but it is not clear to me why.
Copy code
newSuspendedTransaction(context = IO)
s
That is really odd.. On what context is it running before calling
newSuspendedTransaction
?
j
it is inside the kotlin router
Copy code
route("/markup-payments-billi") {
    notarizedPost(markupPaymentBillingOASSpec) {
        effect {
          .....
       }
    }
}
s
What version are you on? I am going to reproduce the issue. Not sure when I'll have time this week, but that is really strange. I cannot think of anything in Arrow that might cause this.
j
Copy code
1.1.5
perhaps it is related to exposed, https://github.com/JetBrains/Exposed/issues/1075
s
Okay, looking at that issue it's definitely exposed. Super strange behavior if you ask me