SrSouza
05/17/2020, 5:29 PMChannel.offer
and Channel.send
, I know that send suspend and offer don't, but what is the usage difference?zak.taccardi
05/17/2020, 6:21 PMflowB
when val flowA: Flow<Boolean>
emits true
, and unsubscribe from flowB
when flowA
emits false
?Joffrey
05/18/2020, 7:31 AMtry {
// some suspending operations to connect to web socket
} catch(e: Exception) {
throw WebSocketConnectionFailedException("meaningful high-level msg", e)
}
But when coroutine machinery like withTimeout
is used around this code, it doesn’t behave as expected (we’re expecting a TimeoutCancellationException
but get another one).
To solve this problem, I add an extra catch to rethrow CancellationException
as-is, but it doesn’t feel right…
try {
// so some operations to connect to web socket
} catch(e: CancellationException) {
throw e // no wrapping here
} catch(e: Exception) {
throw WebSocketConnectionFailedException("meaningful high-level msg", e)
}
Is there a better / built-in way to do this?trathschlag
05/18/2020, 11:29 AMfun scroll() = flow {
try {
// do stuff
} finally {
withContext(NonCancellable) { suspendingCleanUpFunction() }
}
}
This does obviously not work. What would be the correct pattern here?Erik
05/18/2020, 2:58 PMJob
documentation (https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html):
Normal cancellation of a job is distinguished from its failure by the type of its cancellation exception cause. If the cause of cancellation is CancellationException, then the job is considered to be cancelled normally. This usually happens when cancel is invoked without additional parameters. If the cause of cancellation is a different exception, then the job is considered to have failed. This usually happens when the code of the job encounters some problem and throws an exception.From the first sentence I conclude that a coroutine's
CancellationException
may have a cause
. From the second sentence I conclude that the cause
may be yet another CancellationException
, 😕 am I right? And from the fourth sentence I conclude that, if failed, I will receive a CancellationException
with a cause
that is not a CancellationException
, am I right?
So: normally, can a CancellationException
have another CancellationException
as its cause
? If so, can this lead to deep nesting of CancellationException
instances? And, if so, should traverse this chain of cancellation exceptions in search for a different type of exception to determine if this was a failure or normal cancellation?David Glasser
05/18/2020, 11:26 PMStephan Schroeder
05/19/2020, 8:25 AMrunBlocking
an expensive operation? The docs seem to suggest that it’s a good idea to use it once in the main-method and than stay in suspend-country for the rest of the codebase. But how about sprinkling in a bit of concurrent computation here and there with snippets like this:
val (a, b) = runBlocking(Dispatchers.Default) {
val aDeferred = async {getA()}
val aDeferred = async {getB()}
return@runBlocking aDeferred.await() to bDeferred.await()
}
Doable or bad idea?Tolriq
05/19/2020, 12:31 PMVsevolod Tolstopyatov [JB]
05/19/2020, 12:47 PMFlow.cancellable()
operator for cooperative cancellation
• Emissions from flow
builder now check cancellation status and are properly cancellable
• New currentCoroutineContext
function to use unambiguously in the contexts with CoroutineScope
in receiver position
• EXACTLY_ONCE
contract support in coroutine builders.
• Various documentation improvements.taer
05/19/2020, 3:52 PMtaer
05/19/2020, 4:32 PMflow.chunked()
var caughtException = false
val batches = batchResults(inputFlow, chunkSizePerMessage)
.map { createResults(it) }
.catch {
caughtException=true
emit(Results.TerminateWithError(it))
}
emitAll(batches)
if(!caughtException) {
emit(Results.SuccessfulFinish())
}
Ideally, the Successful finish would only be sent on no exceptions from the upstream flow. That var caughtException
seems ugly. Is there a cleaner way?Luis Munoz
05/19/2020, 8:42 PMfunction* generatorFunction(i) {
yield i
yield i +1
}
let gen = generator(5)
gen.next() // value=5, done=false
gen.next() // value=6, done=false
// WHAT I WANT IS THIS
gen.next(100) // <-- here I pass value and get back another value at next yield point
so in generator
it would be let x = yield i to get the input valueRob Elliot
05/19/2020, 9:36 PMsuspend fun <T> Iterable<T>.forEachParallel(
f: suspend (T) -> Unit
) {
coroutineScope {
forEach { t ->
launch {
f(t)
}
}
}
}
tmg
05/20/2020, 8:52 AMasync
executed inside a coroutineScope
finishes before the block exits? (i mean, coroutineScope
waits async
, just like it does for launch
)Dsittel
05/20/2020, 9:50 AMLuis Munoz
05/20/2020, 2:49 PM/**
* Classes and interfaces marked with this annotation are restricted when used as receivers for extension
* `suspend` functions. These `suspend` extensions can only invoke other member or extension `suspend` functions on this particular
* receiver and are restricted from calling arbitrary suspension functions.
*/
@SinceKotlin("1.3")
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
public annotation class RestrictsSuspension
rocketraman
05/20/2020, 9:12 PMbbaldino
05/20/2020, 11:03 PMFoo
(which I don't control) which exposes a field incoming: ReceiveChannel<String>
, and I have a custom type data class MyType(val str: String)
and I want to add an extension field to Foo
to expose a field incomingMyType: ReceiveChannel<MyType>
. What's the best way to wrap the existing channel and map it to produce instances of MyType
containing the String
values? I have something equivalent to the code below working, but wondering if there's any better way. Maybe something with Flow
?
val Foo.incomingMyType: ReceiveChannel<MyType>
get() = produce {
for (str in incoming) {
send(MyType(str))
}
}
dave08
05/21/2020, 8:04 AMStateFlow<Unit?>
can't be used to represent clicks since it's conflated right (unless a new object is created for each emission...)? But SharedFlow
will?myanmarking
05/21/2020, 9:58 AMDsittel
05/21/2020, 10:35 AMArchie
05/21/2020, 2:47 PM@ExperimentalCoroutinesApi
all the time when using coroutines flow?kevin.cianfarini
05/22/2020, 6:18 PMCoroutineScope
that automatically restarts jobs that have failed? Maybe with exponential backoff?Daniel Lukic
05/23/2020, 2:30 PMvoben
05/24/2020, 6:24 PMnapperley
05/25/2020, 11:55 PMLuis Munoz
05/26/2020, 8:09 AMMarc Knaup
05/26/2020, 9:17 AMsessionCoroutineContext
that gets canceled once the user has logged out (i.e. the session is closed).
I have a MessageRepository
that must only be used while the session is open.
Do I now have to wrap every single suspend fun
in my MessageRepository
with withContext(sessionCoroutineContext) { … }
so that they cancel once the session is closed?
Some context:
I still have a scenario where an Android activity is collecting a flow in its viewModelScope
.
An element is collected after the user’s session was closed.
The collector uses the repository which in turn uses the database which in turn tries to access files that no longer exist because the session is closed -> boom.
The idea is to have repository and database properly bound to the session lifecycle so that it doesn’t even try to do anything when the session is gone and throws a cancellation up to the collector.gotoOla
05/26/2020, 9:18 AMprivate suspend fun processAndSend() {
documentService.getDocuments(reference) // returns a Sequence<Documents>
.chunked(10)
.map { chunkedDocuments ->
val processedDocuments = httpClient.processDocuments(chunkedDocuments) // compile error, suspending call
queueSender.send(processedDocuments) // compile error, suspending call
}
}
// compile error = Suspension functions can be called only within coroutine body
Marc Knaup
05/26/2020, 9:31 AMwithContext
check for cancelation upon before and/or after invoking block
?
Will yield
check for cancelation immediately or on/after dispatch?Marc Knaup
05/26/2020, 9:31 AMwithContext
check for cancelation upon before and/or after invoking block
?
Will yield
check for cancelation immediately or on/after dispatch?bezrukov
05/26/2020, 10:07 AMWill a suspending function call check for cancelation before the function implementation is invoked?it's heavily depends on suspend fun implementation, by default suspend fun is not cancellable out of the box, so it needs to be designed to support cooperative cancellation (e.g. use built-in primitives or check for coroutine state).
WillShould be both in generalcheck for cancelation upon before and/or after invokingwithContext
?block
Willcheck for cancelation immediately or on/after dispatch?yield
yield
will check it immediately, but will also resumed with exception if job was cancelled before re-dispatching. Also consider ensureActive
for checking for cancellation in your non-cancellable codeMarc Knaup
05/26/2020, 10:15 AMensureActive
. That seems helpful given that suspend fun
don’t check for cancelation by default (unless it calls others that do).
Do you happen to know a good open source example/library/app that properly manages various scopes & contexts and thus can serve as guidance?louiscad
05/26/2020, 12:08 PMwithContext
since I don't recall which kotlinx.coroutines version does check for cancellation before and after invoking block using its given context (which, in case of NonCancellable
, will be prevented).uli
05/26/2020, 2:28 PMSuspend(Cancelable)Coroutine
, yield
, withContext
, await
, and funs calling one of the above. what did i forget?octylFractal
05/26/2020, 5:10 PMlouiscad
05/26/2020, 7:26 PMJob
.
FYI, the "x" in kotlinx stands for extension.octylFractal
05/26/2020, 8:14 PMlouiscad
05/26/2020, 8:58 PMMarc Knaup
05/27/2020, 7:16 AM