Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Kotlin coroutines [SPR-15413] #19975

Closed
spring-projects-issues opened this issue Apr 4, 2017 · 14 comments
Closed

Add support for Kotlin coroutines [SPR-15413] #19975

spring-projects-issues opened this issue Apr 4, 2017 · 14 comments
Assignees
Labels
has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Apr 4, 2017

Konrad Kamiński opened SPR-15413 and commented

Since 1.1 Kotlin supports coroutines. Its library support includes utility functions for converting suspending functions/lambdas to/from CompletableFuture / Deferred. It would be nice to have such support ListenableFuture as well.

The API could look as follows:

// a function for creating ListenableFuture from suspending lambda
fun <T> listenableFuture(context: CoroutineContext = CommonPool, block: suspend () -> T): ListenableFuture<T>

// a function for creating ListenableFuture from Deferred
fun <T> Deferred<T>.asListenableFuture(): ListenableFuture<T>

// an extension suspending function which awaits for ListenableFuture completion
suspend fun <T> ListenableFuture<T>.await(): T

Affects: 5.0 M5

Issue Links:

Referenced from: pull request #1375

18 votes, 26 watchers

@spring-projects-issues
Copy link
Collaborator Author

Konrad Kamiński commented

I created a pull request.

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

Thanks for contributing this pull request.

Kotlin coroutines seems indeed a good fit for ListenableFuture, but since coroutines are still experimental, I prefer to wait before integrating such support in Spring Framework codebase.

I would suggest submitting a similar pull request on kotlinx.coroutines in order to provide such support like it has been done for Reactor Flux and Mono types. Any chance you could do that?

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

Konrad Kamiński I turn this issue into a global coroutine support one, since there may be other areas than ListenableFuture impacted as shown by your spring-kotlin-coroutine project.

Did you experiment with coroutines + Spring WebFlux? After reading the guide to reactive streams with coroutines, it seems to me this is something worth to explore if we can leverage the existing Reactor based infrastructure of Spring WebFlux (via annotation or functional API) to provide the ability to use imperative style code for those who are not confortable with functional APIs.

That said we really need to experiment in order to see how this work with backpressure, see if it can enable easily to implement custom operator as advertised, etc.
I am quite confident about the ListenableFuture / Mono use case but the Flux use case is less obvious to me.

Any sample WebFlux + coroutine application example could help to move this topic forward.

@spring-projects-issues
Copy link
Collaborator Author

Konrad Kamiński commented

I created a proof-of-concept implementation of mixit application with coroutines. I have not yet touched either WebClient or WebSocket API. The basic approach to introducing coroutines with Spring WebFlux is:

  1. Create a parallel interface/implementation to the existing one, e.g. there is CoroutineServerRequest/DefaultCoroutineServerRequest for ServerRequest which on the one hand is a wrapper around the Reactor based API and on the other provides a coroutines-based API.
  2. For every method which returns a Mono<T> provide instead a suspending function, which returns a T?.
  3. For every method which returns a Flux<T> provide instead a suspending or regular function, which returns ReceivableChannel<T>.

In this poc I only covered whatever was needed for the mixit application to work, though I may have missed something since I have not checked the application thoroughly. I left the tests untouched and they seem to work fine. :)

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

That's super useful Konrad Kamiński thank you! I will have a deeper look to this branch and send you my feedback.

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

I have submitted a pull-request on kotlinx.coroutines to upgrade Reactor coroutine support from Aluminium to Bismuth release train.

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

Reactor Bismuth and Spring Framework 5 support is now available as part of kotlinx.coroutines 0.19.1.

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

Konrad Kamiński Now that Spring Framework 5 and Reactor Core 3.1 are GA + are supported in kotlinx.coroutines, do you have any plan to add WebFlux support to your great project https://github.com/konrad-kaminski/spring-kotlin-coroutine ? Based on what you did on MiXiT application, and now that our APIs are stable, I guess it could be useful for Spring + Kotlin developers to have CoroutineFoo variants of the ReactiveFoo main existing ones, + provide some extensions to have a bridge between the 2 worlds ? I would be interested to have your thoughts on this.

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

Some additional thoughts about bridging Reactor-based APIs to Coroutines based on your previous experiment.

For streaming use case, Flux<T> -> suspending function which returns ReceivableChannel<T> should be fine. On that topic, it seems that channel operators are coming on Coroutine side.

For non streaming use cases, maybe most of the time translating Flux<T> -> suspending function which returns List<T> via a preliminary call to Flux.collectList() will be more efficient and more familiar with the programming model people have in non-Reactive world and in line with the goal of Coroutines to provide a simplified imperative like programming model.

Mono<T> could translate to suspending function which returns T (most of the time) or T? depending on the context (should be specified in the Javadoc, if not please raise an issue).

Mono<Void> could translate to suspending function which returns Unit.

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

See this PR comment.

@spring-projects-issues
Copy link
Collaborator Author

Sébastien Deleuze commented

A quick update:

@spring-projects-issues spring-projects-issues added type: enhancement A general enhancement in: core Issues in core modules (aop, beans, core, context, expression) has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 5.2 RC1 milestone Jan 11, 2019
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Feb 18, 2019
This commit is the first part of a more complete Coroutines
support coming in Spring Framework 5.2. It introduces suspendable
Kotlin extensions for Mono based methods in WebFlux classes like
WebClient, ServerRequest, ServerResponse as well as a Coroutines
router usable via `coRouter { }`.

Coroutines extensions use `await` prefix or `AndAwait` suffix,
and most are using names close to their Reactive counterparts,
except `exchange` in `WebClient.RequestHeadersSpec`
which translates to `awaitResponse`.

Upcoming expected changes are:
 - Leverage `Dispatchers.Unconfined` (Kotlin/kotlinx.coroutines#972)
 - Expose extensions for `Flux` based API (Kotlin/kotlinx.coroutines#254)
 - Introduce interop with `CoroutineContext` (Kotlin/kotlinx.coroutines#284)
 - Support Coroutines in `ReactiveAdapterRegistry`
 - Support Coroutines for WebFlux annotated controllers
 - Fix return type of Kotlin suspending functions (spring-projectsgh-21058)

See spring-projectsgh-19975
@sdeleuze
Copy link
Contributor

sdeleuze commented Feb 18, 2019

Coroutines support for WebClient and WebFlux.fn has been merged in master branch via this commit which is the first part of a more complete Coroutines support coming in Spring Framework 5.2. It introduces suspendable Kotlin extensions for Mono based methods in WebFlux classes like WebClient, ServerRequest, ServerResponse as well as a Coroutines router usable via coRouter { }. See more details in the Coroutines section of the reference documentation.

Coroutines extensions use await prefix or AndAwait suffix, and most are using names close to their Reactive counterparts, except exchange in WebClient.RequestHeadersSpec which translates to awaitResponse.

Upcoming expected changes are:

I am also preparing pull-requests for Spring Data MongoDB and Spring Data R2DBC.

A demo project is available in this spring-boot-coroutines-demo repository.

sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 15, 2019
This commit turns Coroutines suspending methods to `Mono` which can be
handled natively by WebFlux.

See spring-projectsgh-19975
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 15, 2019
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 15, 2019
@sdeleuze
Copy link
Contributor

Support for WebFlux annotated controllers, including view resolution and Deferred, has been merged in master branch. See this sample Coroutines controller for a concrete example.

sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 15, 2019
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 25, 2019
This commit introduces the spring-core-coroutines module
in order to avoid referencing Kotlin code from Java one,
which is currently not supported by Eclipse.

During the build, spring-core-coroutines is merged into
spring-core, so this change is expected to have no impact
for end users.

This module contains functions accessible from Java via
the CoroutinesUtils class to adapt Coroutines and Deferred
instances to and from Mono.

See spring-projectsgh-19975
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 27, 2019
As of Coroutines 1.2.0-alpha, Dispatchers.Unconfined
is a stable API so we can leverage it in order to get
better performance in our Reactive to Coroutines
bridge.

See spring-projectsgh-19975
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 28, 2019
This commit provides both nullable and non-nullable variants for
awaitBody, makes awaitPrincipal return type nullable and rename
awaitResponse to awaitExchange for better consistency with Java API.

See spring-projectsgh-19975
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 31, 2019
This commit also switches on kotlin-compiler-embeddable to
improve isolation of its dependencies

See spring-projectsgh-19975
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Mar 31, 2019
As of Coroutines 1.2.0-alpha, Dispatchers.Unconfined
is a stable API so we can leverage it in order to get
better performances in our Reactive to Coroutines
bridge.

See spring-projectsgh-19975
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Apr 2, 2019
sdeleuze added a commit to sdeleuze/spring-framework that referenced this issue Apr 4, 2019
@sdeleuze
Copy link
Contributor

sdeleuze commented Apr 4, 2019

With Coroutines Flow support (see this commit), Spring Framework Coroutines support is now complete. See https://github.com/sdeleuze/spring-boot-coroutines-demo for concrete examples of Flow usage and also see :

A detailed blog post is coming next week to present an overview of Spring Coroutines support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has: votes-jira Issues migrated from JIRA with more than 10 votes at the time of import in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants