Does Spring-Boot handle Kotlin coroutines apart from WebFlux context? - spring-boot

We are trying to use Kotlin coroutines for asynchronous processing inside Spring-Boot backend.
The problem is that it doesn't seem to support it well (At least standard Spring MVC).
Basically, if we have a function that does asynchronous logic:
fun fetchUsersAsync(): Deferred<Users> {
return GlobalScope.async {
...
}
}
and this function is used with await at some point in service, which requires to put suspend annotation in a calling service function:
#Service
class MyService {
suspend fun processUsers(): Users {
return fetchUsersAsync().await()
}
}
Unfortunately it is not possible, and the only reference for suspend functionality in service was connected with WebFlux.
Has anyone faced the same situation? Thanks.

If you want to call await() without declaring a suspend function, wrap it inside a coroutine builder, like this:
#Service
class MyService {
fun processUsers(): Users {
return runBlocking { fetchUsersAsync().await() }
}
}

Related

How to use kotlin coroutines with reactive spring data

I am trying to migrate some project from Spring Reactor to kotlin coroutines. I have some controller based on spring webflux like that:
#RestController
class Controller(val productRepository: ProductsRepository) {
#GetMapping("/product")
fun find(#RequestParam id: String): Mono<Product> {
return productRepository.findById(id)
}
}
This controller uses reactive spring data repository:
#Repository
interface ProductsRepository : ReactiveMongoRepository<Product, String>
According to this official documentation - https://docs.spring.io/spring/docs/5.2.0.M1/spring-framework-reference/languages.html#how-reactive-translates-to-coroutines, my function find in controller should be translated to suspend fun and this function should return an instance of Product class instead of reactive Mono wrapper of Product. Something like that:
#RestController
class Controller(val productRepository: ProductsRepository) {
#GetMapping("/product")
suspend fun find(#RequestParam id: String): Product {
return productRepository.findById(id)
}
}
But my productRepository deals with Mono and Flux, not suspended functions. How should I use spring data abstraction properly in that case?
This can be achieved with the useful kotlinx-coroutines-reactor helper library which provides useful extensions methods for project reactors Publisher to help between converting Mono or Flux to kotlin coroutines.
First add a dependency on
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-reactor</artifactId>
</dependency>
(if your using spring-boot you do not have to specify a version as it manages it for you)
You can now use kotlinx.coroutines.reactive.awaitFirstOrNull to convert a Mono<Product> to Product? and 'await' the result.
#RestController
class Controller(val productRepository: ProductsRepository) {
#GetMapping("/product")
suspend fun find(#RequestParam id: String): Product? {
return productRepository.findById(id).awaitFirstOrNull()
}
}

Convert Spring Cloud Stream to use reactive cloud function

Currently I have Spring Boot application which is something like this.
#Component
#EnableBinding(Source::class)
class EmailMessageProducer(private val source: Source) {
suspend fun send(textMessage: TextMessage) {
source.output().send(
MessageBuilder.withPayload(textMessage).setHeader("service", "test").build()
)
}
}
I would like to use Spring Cloud Function here using reactive pattern.
Furthermore, is my current solution non blocking? I am asking this because this is my first time using Kotlin coroutine in this context.
Java solution works for me as well since I am just trying to understand the concept here.
What you're looking for is a reactive Supplier (e.g., Supplier<Flux>).
In your case it would look something like this:
#SpringBootApplication
public class SomeApplication {
#Bean
public Supplier<Flux<Message<String>>> messageProducer() {
return () -> Flux.just(MessageBuilder.withPayload(textMessage).setHeader("service", "test").build());
}
}
Provide spring.cloud.function.definition=messageProducer property and this is pretty much it.
Obviously the above example produced a finite stream with a single item, but feel free to modify the returned flux. In fact we discuss this in more details here.

Spring + Kotlin - Is it possible to detect certain functions calls?

I've just started using Spring and Kotlin and wanted to ask is it possible for my app to detect certain function calls?
For example, say I have:
fun getSuccessMessage() : String {
return "great"
}
Then in my app runner I call that:
#Component
class AppRunner: CommandLineRunner {
#Throws(Exception::class)
override fun run(vararg args: String) {
getSuccessMessage()
}
}
Can I have another function thats listening and acts whenever its called:
fun doSomethingWhenSuccessCalled() {
// I'm imaging some magic Spring annotation where I can say
//something like #ListeningTo("getSuccessMessage")
}
No, it is not possible.
To read more about listener of method invoke look at:
Listener on Method.invoke java

Obtaining the result of a Mono in order to pass it onto a JpaRepository or another non reactive class

I would like to know what is the appropriate way obtaining an object from a Mono (or Flux) to pass onto a non-reactive method such as a JpaRepository.
Here is the way I did it:
#Service
public class ReactiveAccountService {
//AccountService's methods take non-mono/non-flux objects as arguments
private AccountService accountService;
public ReactiveAccountService(AccountService accountService) {
this.accountService = accountService;
}
public Mono<Void> signUp(Mono<Account> accountMono) {
//Account is a Jpa entity
accountMono.subscribe(account -> accountService.signUp(account));
return Mono.empty();
}
}
How can this be improved? Can someone please advise?
The better way to do that is like this:
public Mono<Void> signUp(Mono<Account> accountMono) {
//Account is a Jpa entity
return accountMono.flatMap(account -> {
accountService.signUp(account);
return Mono.empty();
});
}
This way you follow Reactive Streams requirements and don't bother the execution flow with your blocking code. Plus according the Spring WebFlux requirements you don't subscribe in your own code, but deffer everything to the container which is an initiator of that Mono<Account>. The actual execution will happen, when there is enough resources in the Web (Reactive) container to subscribe to the returned Mono.

Spring Controller - forking request, return value before long run function ends

I have controller and long run function in it, like:
#Controller
#RequestMapping("/deposit")
public class DepositController {
#RequestMapping
public ModelAndView getNewJob(long userId, Model model) {
//execute function that can runs a lot of time ...
longRunFunction();
return new ModelAndView("jobTasks");
}
public void longRunFunction(){
// process long run function
}
}
My question is :
How can I execute the longRunFunction()
and return ModelAndView("jobTasks") answer to the browser without waiting for the end of the function?
Thank you !
Hi, I found nice example here http://krams915.blogspot.co.il/2011/01/spring-3-task-scheduling-via.html
This can be done using Asynch support in Spring Framework, essentially delegate the long running task to another service, the method of which is annotated with #Async annotation, this task would then be executed by a threadpool and control will return back to your caller immediately.
Here is much more detailed reference: http://docs.spring.io/spring-framework/docs/3.2.3.RELEASE/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-async
public class SampleBeanImpl implements SampleBean {
#Async
void longRunFunction() { … }
}
Add #Async to the method declaration of longRunningMethod. But to make this work without AspectJ weaving you need to put this method in an other bean.

Resources