Hi there. I need a general advice on using arrow w...
# arrow
j
Hi there. I need a general advice on using arrow with atomic "update-and-get" like behaviour with suspending calls inside. Is it even possible?
s
Hi Jakub! I just checked and the Kotlin Std doesn't offer these parameters 😅 They can also easily be added as extension functions over the new
kotlin.concurrent.atomics
package. It possible due to the function being defined
inline
, but it's generally bad practice because slow operations are prone to being conflicting. The problem with
update
& co is that they run in a loop under the hood, so if another operation changes the value the
update
function is run again. So if you have a fast operation vs a slow operation than the fast operation will always win, and the slow operation will run in a loop because it's never fast enough to update the value in an atomic way.
j
yeah the more time I spent looking at it, the more convinced I am that I don't want to risk deadlock in my particular case 🙂
s
Depending on what you want to do a different approach is typically used. I had a small example documented on an old type in Fx that no longer exists, it had a
modify
function that allows you to modify the atomic state and extract information from that operation. It requires a split between "state management" and executing the required work afterwards. This pattern can be used to safely implement a semaphore, and other complex concurrency types. https://github.com/arrow-kt/arrow/blob/9579e10672e41d740521e9a30f3d7367a01f430c/ar[…]-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Atomic.kt
j
basically I wanted to do something like
Copy code
private val cache = Atomic<State>(State(Instant.now(), some, other, data))

fun refreshIfNeeded() = cache.updateAndGet { prev ->
    if (state.timestamp > Instant.now().minusSeconds(5)) prev
    else myKtorBasedClient.performSuspendingNetworkFetch()
  }
But I decided that it's not work the risk, at worst case scenario I'll get one or two concurrent calls to server, which does not hurt me at all 🙂
c
Hey, the problem you’re describing is prone to cache stampede, where refresh is needed could be invoked by more than one caller. You should gate the update mechanism with an atomic bool, flipping it so only one user gets in. Then make the call only for that path and serve a stale entry for everyone else in the interim
👍 1