davidasync
01/28/2019, 4:09 PMsvenjacobs
01/29/2019, 7:01 AMCoroutineScope
? Let's say I have a function that calls launch
. I could do it like this:
fun doSomething() {
GlobalScope.launch {
...
}
}
but what if I want the launch
block to be tied to the outer scope? So if the outer scope is terminated so should the launch
block. What I tried is
fun doSomething(scope: CoroutineScope) {
scope.launch {
...
}
}
but it doesn't feel right. Or should I better use
suspend fun doSomething() {
coroutineScope {
launch {
...
}
}
}
but then I create a new scope, right?elizarov
01/29/2019, 7:19 AMdoSomething
to do:
• If you want to wait until it finishes doing its work you write suspend fun doSomething() = coroutineScope { ... }
• If you want it to return quickly with a side effect of launching new coroutine, you write fun CoroutineScope.doSometing() = launch { ... }
.rrva
01/29/2019, 7:22 AMprivate fun <A, B> Iterable<A>.parallelMap(context: CoroutineContext, f: suspend (A) -> B): List<B> = runBlocking {
map { async(context) { f(it) } }.map { it.await() }
}
val listOfIds.parallelMap(fooApiPool) { fooApiClient.fetchStuff(it)}
(found at: https://jivimberg.io/blog/2018/05/04/parallel-map-in-kotlin/)
But what about orchestrating calls to several sources (clients calls could be made suspendable if this is important), where we for example have three source API:s which we would like to be called in parallel, and then the values are awaited and collected? (I'm trying to get rid of RxJava for some use-cases where I found it to be a burden to maintain/debug). What are good patterns here for expressing the execution flow?ARnikev
01/29/2019, 10:17 AMfun doSomething(someBody: Body): Mono<Void> {
return client
.patch()
.uri("/someuri")
.accept(APPLICATION_JSON_UTF8)
.contentType(APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(someBody))
.retrieve()
.bodyToMono(Void::class.java)
.onErrorMap {
BusinessServiceException("CODE", "TITLE").apply {
httpStatus = HttpStatus.FORBIDDEN
detail = "some detail"
}
}
}
To invoke this method in non-blocking way i do following thing:
try {
clientBean.doSomething(someBody).awaitFirst()
} catch (e: Exception) {
throw e
}
What i expect is that in case of exception in webclient call there has to be BusinessServiceException caught in catch block above.
And BusinessServiceException fields (code, title, httpStatus, detail) have to be populated with values that i’ve set in onErrorMap method on webclient mono response.
What i really have is BusinessServiceException with null fields (code, title, httpStatus, detail) and cause field populated with expected by me BusinessServiceException (with all fields filled the same way as i’ve set them in onErrorMap method).
BusinessServiceException class looks like this:
public class BusinessServiceException extends ServiceException {
public BusinessServiceException(String code, String title) {
super(code, title);
}
public BusinessServiceException(String message, Throwable cause) {
super(message, cause);
}
}
I’ve tried to debug all this stuff and it seems like that BusinessServiceException’s constructors called 2 times.
First time, as expected, the public BusinessServiceException(String code, String title)
constructor is called, in onErrorMap() method.
Second time, unexpectedly, the public BusinessServiceException(String message, Throwable cause)
constructor is called, somewhere in private suspend fun <T> Publisher<T>.awaitOne -> override fun onError(e: Throwable) { cont.resumeWithException(e)}
method, and that call wraps original exception in exception of the same type but with null fields (because of wrong constructor call).
I couldn’t find the exact place where this constructor could be called.
Interesting thing is if i delete this second constructor public BusinessServiceException(String message, Throwable cause)
from the BusinessServiceException.class - everything works as expected.
I would really appreciate any thoughts on this.withoutclass
01/29/2019, 3:46 PMtseisel
01/29/2019, 9:03 PMDalinar
01/30/2019, 4:49 AMfuture { }
?sdeleuze
01/30/2019, 1:47 PMWebClient
and the functional server API) is currently designed as extensions (https://github.com/spring-projects/spring-fu/tree/master/coroutines/webflux) since the API surface is big and only a small part is IO related. For methods returning Mono
I am just using Publisher<T>.awaitSingle()
or Publisher<T>.awaitFirstOrNull()
, no problem there. For method where I need to create a Mono
from a Coroutine this is less clear to me. I am currently doing GlobalScope.mono(Dispatchers.Unconfined) { ... }
since with an extension I don't see how I should use constructs like fun CoroutineScope.doSometing() = mono { ... }
. How I am supposed to handle that when using extensions? Also I am not really leveraging structured concurrency here, but since I am exposing a Reactive Streams core with Coroutines I am not sure yet if this is an issue or not.
Support for Spring Data MongoDB (https://github.com/spring-projects/spring-fu/tree/master/coroutines/data-mongodb) and R2DBC (https://github.com/spring-projects/spring-fu/tree/master/coroutines/data-r2dbc) is based on dedicated Coroutines API since almost all the API is related to IO operation, I have used Co
prefix like for CoDatabaseClient
for example (https://github.com/spring-projects/spring-fu/blob/master/coroutines/data-r2dbc/src/main/kotlin/org/springframework/data/r2dbc/function/CoDatabaseClient.kt).
Translating Flux
support depends on https://github.com/Kotlin/kotlinx.coroutines/issues/254 so I have not started this part yet.
I also still need to implement interop between Reactor and Coroutines context https://github.com/Kotlin/kotlinx.coroutines/issues/284
This is really the early stage, and I am not yet super familiar with Coroutines, so any feedback welcome.asad.awadia
01/30/2019, 2:41 PMasad.awadia
01/30/2019, 2:41 PMansman
01/30/2019, 3:21 PMsuspend
. It would be great to have a property that is backed by a Deferred
curioustechizen
01/30/2019, 3:34 PMstreetsofboston
01/30/2019, 3:45 PMclass LogicTest {
private lateinit var viewmodel: ViewModel
private var repo: IRepository = mockk(relaxed = true)
@BeforeEach
fun setUp() {
viewmodel = ViewModel(repo, Dispatchers.Unconfined)
}
@Test
fun `when ViewModel init called then it calls repo init`() {
viewmodel.init()
verify { repo.init() }
}
@Test
fun `when ViewModel getName called then it calls repo getName`() {
viewmodel.getName { }
runBlocking {
coVerify { repo.getName() }
}
}
}
Note that I used MockK for the testing framework, not Mockito, but that should not matter.
Update: Using Dispatchers.Unconfined is good enough for these tests.
There is a known issues with Mockito verifying coroutines, but that should have been fixed in the latest version.julioyg
01/30/2019, 4:27 PMansman
01/30/2019, 6:43 PMJob
a large object? Should I remove old jobs or should they be cleaned up ASAP?Dalinar
01/30/2019, 7:00 PMisCompleted
means cancelled or completed, `isCancelled`means cancelled, so to find out if it completed sucessfully there is no easier way than checking for isCompleted && !isCanclled
?Max Russek
01/30/2019, 10:38 PMasad.awadia
01/31/2019, 2:45 AMahulyk
01/31/2019, 2:39 PMlaunch(IO) {
val result = repoRepository.getAllRepos()
withContext(Main) {
textField.text = result
}
}
Example 2:
launch(Main) {
val result = repoRepository.getAllRepos()
withContext(Main) {
textField.text = result
}
}
Question is why i'm not getting android.os.NetworkOnMainThreadException in second example?Dias
01/31/2019, 5:16 PMselect
statement, etcrrva
01/31/2019, 8:25 PMContinuation
parameter?streetsofboston
02/01/2019, 4:25 AMscope.coroutineContext[ContinuationInterceptor]
hmgeorge
02/01/2019, 5:08 AMDalinar
02/01/2019, 5:55 AMpajatopmr
02/01/2019, 8:39 AMahmad
02/01/2019, 12:08 PMkoufa
02/01/2019, 3:46 PMfun main() = runBlocking {
try {
cScope()
} catch (error: Throwable) {
println(error)
}
}
suspend fun cScope() = coroutineScope {
val def = async { failure() }
try {
def.await()
} catch (error: Throwable) {
println(error)
}
}
Why is it only possible to catch
the error when wrapping cScope()
and not def.await()
?gergo
02/01/2019, 5:39 PMPaul Woitaschek
02/02/2019, 9:22 PMsuspend fun <http://CoroutineContext.xyz|CoroutineContext.xyz>()
and I perform a check and then call coroutineContext.cancel()
and then throw a CancellationException
.Paul Woitaschek
02/02/2019, 9:22 PMsuspend fun <http://CoroutineContext.xyz|CoroutineContext.xyz>()
and I perform a check and then call coroutineContext.cancel()
and then throw a CancellationException
.Allan Wang
02/02/2019, 9:22 PMAllan Wang
02/02/2019, 9:23 PMyield()
Paul Woitaschek
02/02/2019, 9:23 PMAllan Wang
02/02/2019, 9:23 PMsuspend
and CoroutineScope
extensions in one method. Suspending functions are long executions whereas coroutine scope functions launch and return quicklyPaul Woitaschek
02/02/2019, 9:26 PM