hi - i’m wondering why `Either.catch` is strict in...
# arrow
p
hi - i’m wondering why
Either.catch
is strict in evaluating it’s supplied function, is there a way to catch an Exception from an effect? eg
Copy code
suspend findThing(): Thing {} 

Either.catch { findThing() } // ???
s
It’s inline so you can call a suspending function inside the lambda as long as you’re in another suspending scope
p
the parameter function passed to
catch
isn’t inline or suspend?
message has been deleted
s
Is the function suspend?
p
yes
see context hovering box in the screenshot ^
s
Strange, this works fine for me and I’m also using exposed
In production
p
interesting… are you using exposed with
newSuspendedTransaction
vs
transaction
?
s
Both
Both within catch
What version are you on?
p
i definitely understand why the compiler is complaining:
Copy code
inline fun <R> catch(f: () -> R): Either<Throwable, R> =
f
is not marked
inline
or
suspend
s
It doesn’t need to be since the function is marked inline
p
arrow 0.13.2 exposed: 0.32.1
s
Can you build from cli?
p
sure, sec
Copy code
ContractLifecycleTable.kt: (201, 21): Suspension functions can be called only within coroutine body
s
mind blown
p
actually… i’m sorry this must be something on my side
it’s a lambda inside another block.. if i move it out.. it compiles 😞
s
Oh, no worries. Having function inlined is really powerful for suspension, can be annoying if some libraries hinder it
If you own that function marking it inline should fix the issue
🙏 1
p
btw, i vaguely remembering raul shared a gist you created a while ago for … i think retrying db operations, does that ring any bells?
s
Yes, but it was for SqlDelight
p
ahhh ok
s
If you’re interested in retrying you can check Schedule docs
Or this new one sec
p
i need to dig into schedule. i’ve ported the haskell retry library to kotlin (though.. it’s not especially effect aware & pure .. yet)
There is a composeable Schedule type in Fx
p
oooh yea, definitely need to dig into that
do you by any chance have a nice way of retrying transient exceptions thrown by exposed?
eg
Copy code
org.jetbrains.exposed.exceptions.ExposedSQLException: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 5004ms.
i just tried cobbling something together quickly but i probably need to take a step back and reevaluate my strategy
Copy code
private suspend fun <T>runWithContextAndTransaction(block: Transaction.() -> T): Either<Throwable, T> {
        return withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            retrying(
                defaultRetryPolicy,
                ::eitherDecider,
                onRetry = logRetry(logger, defaultRetryPolicy),
            ) {
                Either.catch {
                    newSuspendedTransaction {
                        block()
                    }
                }
            }
        }
    }
s
Ye, I have something for this. It works based on a predicate for exposed exceptions, and it’s wrapped in schedule and circuit breaker and it comes out Either<Throwable, A> I will share it here tomorrow
p
sounds perfect, thank you!! 🙏
s
It looks similar to the resilience function in the circuit breaker docs
👀 1
c
Is your outside function marked as
suspend
? If it's not, then the error makes sense
Copy code
fun foo() {
  // outer function is not suspend
  Either.catch {
    // Therefore ‘catch’, despite being inline, can't suspend (it would be inlined in a non-suspending function)
Copy code
whatever() // if this function is marked as ‘suspend’, it can't be called here
  }
}