Jan
07/31/2021, 11:53 PMmarcinmoskala
08/02/2021, 8:06 AMAnoop Gopalakrishnan
08/02/2021, 10:12 PMjuan torres
08/03/2021, 7:11 AMasync
and withContext(<http://Dispatches.IO|Dispatches.IO>)
to be able to execute blocking code, in particular making multiple IO calls with Spring RestTemplate, in an asynchronous fashion like so:
fun <T> CoroutineScope.myRestTemplateAsync(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T> {
return async(context, start) {
withContext(<http://Dispatchers.IO|Dispatchers.IO>) { block() }
}
}
The full description, observations, and code samples are in this SO Postpgreze
08/03/2021, 9:00 AMnatario1
08/03/2021, 1:44 PMFlow<State>
that represents some state and a Channel<Event>
? Regular combine(...) does not work well, because the event should only be processed once (against the most recent state). I currently achieve this with a pretty complex channelFlow { } with two coroutines and saving stuff in local `var`s, but I wonder if there's a smarter way.Glen
08/03/2021, 8:39 PMandylamax
08/04/2021, 1:16 AMmuthuraj
08/04/2021, 7:58 AMFlow.debounce
? The unit test doesn't wait until debounce is completed. It should actually advance the delay since I'm using runBlockingTest
as per the documentation, but that doesn't happen. Here is an example that reproduces my case.
class DebounceTest(scope: CoroutineScope) {
private val stateFlow = MutableStateFlow("")
val resultFlow = MutableStateFlow("")
init {
stateFlow.debounce(500)
.onEach {
resultFlow.value = it
}
.launchIn(scope)
}
fun search(text: String){
stateFlow.value = text
}
}
@Test
fun debounceTest() = runBlockingTest {
val sut = DebounceTest(this)
sut.search("test")
assertThat(sut.resultFlow.value).isEqualTo("test")
}
The test here fails saying the actual value of resultFlow.value
is empty string instead of test
Daniele Segato
08/04/2021, 7:59 AMrunBlockingTest {
val mutex = Mutex(true)
val mockedApi = mock<MyApi> {
onBlocking { invoke() } doSuspendableAnswer {
mutex.withLock {
// wait unlock to run
}
}
}
val sut = MyTestedClass(
api = mockedApi,
)
println("async callA"}
val callA = async { sut.doCall() }
println("async callB"}
val callB = async { sut.doCall() }
mutex.unlock()
// ....
}
this test never completes, it runs forever and stop at async callA
the async callB
is NEVER printed
the MyTestedClass
class MyTestedClass(private val api: MyApi) {
fun doCall() { // this is NOT suspendable
runBlocking {
api() // but this is suspendable
}
}
}
Isn't async supposed to be non-blocking? I would expect callA and callB to be executed concurrently until they reach the mutex but apparently the first async is blocking in the test and stop at the mutex blocking all the test.
What am I missing here?julioromano
08/05/2021, 11:02 AMdoSomething
call the 3 suspending functions serially? (i.e. waiting for each one to complete before calling the other?)
suspend fun doSomething() {
suspendingFun1()
suspendingFun2()
suspendingFun3()
}
🧵napperley
08/06/2021, 1:50 AMMarty Pitt
08/06/2021, 10:22 AMPHondogo
08/07/2021, 12:36 PMMarc Knaup
08/07/2021, 10:16 PMsuspend fun main() {
flow {
flowOf(1).collectLatest { emit(it) }
}.collect { println(it) }
}
IllegalStateException: Flow invariant is violated
Aaron Waller
08/09/2021, 9:58 AMwith(GlobalScope){ launch{} }
and GlobalScope.launch{}
? All I can find is: "You can use with()
in order to avoid the repetition of the GlobalScope
receiver" but I don't really get it.
Thanks in advanceStefan Oltmann
08/09/2021, 11:03 AMVivek Modi
08/09/2021, 1:13 PMapi
from object
class. I am new in Coroutines. That API call should be executer concurrently and app's flow should not wait for result of that call. I tried some code, but i am not sure is it correct way of doing it or not. Also i got a error`Process: com.dimen.app, PID: 12496`
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1605)
private fun setupLogout() {
logoutButton.setOnClickListener {
LoginHelper.logout()
}
}
fun logout() {
logD("logout")
deleteSession()
.... more function
}
private fun deleteSession() {
runBlocking {
Tokenclass.getToken()?.let {
logE("token ::-> $it")
apiCall.deleteSession(it).execute()
}
}
}
Slackbot
08/09/2021, 7:26 PMRob
08/10/2021, 8:32 PMeygraber
08/11/2021, 4:28 AMinterface MyDispatchers {
val main: CoroutineDispatcher
val io: CoroutineDispatcher
val computation: CoroutineDispatcher
val unconfined: CoroutineDispatcher
}
Instead of using Dispatchers.*
I use one of the properties from `MyDispatchers`(which are set to the corresponding Dispatchers.*
)
Is this necessary, or does the coroutines test artifact have a construct that allows you to use Dispatchers.*
and control them during a test?Richard Gomez
08/11/2021, 7:14 PMexpensiveLookup
only executes once (for a given id) and subsequent executions receive the cached value?
suspend fun expensiveLookup(id: String): ExpensiveResult {
val cached = cache.get(id)
if (cache != null) {
return cached
}
val result = // logic here
cache.put(id, result)
return result
}
This blog post from Doordash in 2018 has an interesting solution. Is there a 'better' way of doing this now?
https://doordash.engineering/2018/08/03/avoiding-cache-stampede-at-doordash/Jimmy Alvarez
08/12/2021, 3:12 AMcoroutineScope.launch {
// some work
}
coroutineScope.launch {
// some other work
}
In my understanding, this should not block the thread given i’m launching both coroutines concurrently. but what is happening is that first coroutine blocks the thread so the second coroutine never gets executed.
The only way I could make it run concurrently was to wrap // Some work
into a suspend
function, then I got the concurrent execution
Could you explain a little why this only work by using the suspend function inside coroutine?Lefko
08/12/2021, 8:22 AMjava.lang.IllegalArgumentException: userUUID must not be empty
corneil
08/12/2021, 11:17 AMchristophsturm
08/12/2021, 2:00 PMBrendan Campbell-hartzell
08/13/2021, 4:54 AMK Merle
08/13/2021, 6:49 AMritesh
08/13/2021, 8:31 PMcoroutineScope.coroutineContext.cancelChildren
vs coroutineScope.cancel
They both cancels all the childrens.efemoney
08/14/2021, 10:55 AMStateFlow
) … will this be a good way?
interface RefreshableFlow: Flow (or SharedFlow or StateFlow) {
fun refresh()
}
class RefreshableFlowImpl(val delegate: flow): Flow by flow, RefreshableFlow {
override fun refresh() { ... } // launch coroutine/send event/etc that would eventually or not emit a new value
}
What are the pitfalls of doing something like this?efemoney
08/14/2021, 10:55 AMStateFlow
) … will this be a good way?
interface RefreshableFlow: Flow (or SharedFlow or StateFlow) {
fun refresh()
}
class RefreshableFlowImpl(val delegate: flow): Flow by flow, RefreshableFlow {
override fun refresh() { ... } // launch coroutine/send event/etc that would eventually or not emit a new value
}
What are the pitfalls of doing something like this?Erik
08/14/2021, 1:15 PMefemoney
08/14/2021, 1:20 PMErik
08/14/2021, 1:22 PMefemoney
08/14/2021, 1:32 PMinterface X { val flow: Flow ; fun refresh() }
is (necessarily) a better API.
For one at the callsite, it becomes x.flow.collect { ... }
vs x.collect { ... }
which may be less desirable depending on the concept x
is meant to represent.
Also for the same reason why (I imagine) StateFlow
is not defined as
interface StateFlow<T> { val flow: Flow ; val value: T}
what I want is a “flow that can be refreshed” and not an “entitity that has a flow and can be refreshed”Erik
08/14/2021, 1:34 PM