How to correctly use suspend functions with coroutines on webflux? - reactive-programming

I'm new to reactive programming and because I've already used kotlin with spring-web in the past, I decided to go to spring-webflux on this new project I'm working on. Then I discovered Mono and Flux apis and decided to use spring-data-r2dbc to keep full reactive stack (I'm aware I don't know how far this new project could be from meeting all reactive expectations, I'm doing this to learn a new tool, not because this is the perfect scenario for this new tool)
then I noticed I could replace all reactive streams apis from webflux with kotlin's native coroutines. I also opted by coroutines simply to learn and have less 'external frameworky' code
my application is quite simple (it's an url shortener):
1. parse some url out of http request's body into 3 parts
2. exchange each part to its postgres id on each respective table
3. concat these 3 ids into a new url, sending an 200 http response with this new url
my reactive controller is
#Configuration
class UrlRouter {
#Bean
fun urlRoutes(
urlHandler: UrlHandler,
redirectHandler: RedirectHandler
) = coRouter {
POST("/e", urlHandler::encode)
GET("/{*url}", redirectHandler::redirect)
}
}
as you can imagine, UrlHandler is responsible for the steps numbered above and RedirectHandler does the oposite: receiving an encoded url, it redirects to the right url received on number 1.
question 1: checking on coRouter, I assumed that for each http call, spring will start a new coroutine to resolve that call(oposing to a new thread on traditional spring-web), and each of these can create and depend on several other sub coroutines. Is this right? Does this hierarchy exist?
here's my UrlHandler fragment:
#Component
class UrlHandler(
private val cache: CacheService,
#Value("\${redirect-url-prefix}") private val prefix: String
) {
companion object {
val mapper = jacksonObjectMapper()
}
suspend fun encode(serverRequest: ServerRequest): ServerResponse =
try {
val bodyMap: Map<String, String> = mapper.readValue(serverRequest.awaitBody<String>())
// parseUrl being a string extension function just splitting
// that could throw IndexOutOfBoundsException
val (host, path, query) = bodyMap["url"]!!.parseUrl()
val hostId: Long = cache.findIdFromHost(host)
val pathId: Long? = cache.findIdFromPath(path)
val queryId: Long? = cache.findIdFromQuery(query)
val encodedUrl = "$prefix/${someOmmitedStringConcatenation(hostId, pathId, queryId)}"
ok().bodyValueAndAwait(mapOf("url" to encodedUrl))
} catch (e: IndexOutOfBoundsException) {
ServerResponse.badRequest().buildAndAwait()
}
all three findIdFrom*** calls try to retrieve an existing id and if it doesn't exist, save new entity and return new id from postgres sequence. This is done by CoroutineCrudRepository interfaces. Since my methods should always suspend, all 3 findIdFrom*** also suspend:
#Repository
interface HostUrlRepo : CoroutineCrudRepository<HostUrl, Long> {
suspend fun findByHost(host: String): HostUrl?
}
question 2: looking here I've found either invoke reactive query methods or have native suspended functions. Since I've read methods should always suspend, I've decided to keep myself using suspend. Is this bad/wrong in any way?
these 3 findIdFrom*** are independent and could be called to run in parallel and then only at someOmmitedStringConcatenation I should wait for any unfinished calls to actually build my encoded url
question 3: since every single method has the suspend modifier, it will run exactly as on traditional imperative sequential paradigm (wasting any benefit from parallel programming) ?
question 4: is this a valid scenario for coroutines usage? If so, how should I change my code to best fit the parallelism I want above?
possible solutions I've found for question 4:
question 4.1: source 1 inside each findIdFrom*** wrap it with withContext(Dispatchers.IO){ /*actual code here*/ } and then on encode function:
coroutineScope {
val hostIdDeferred = async { findIdFrom***() }
val pathIdDeferred = async { findIdFrom***() }
val queryIdDeferred = async { findIdFrom***() }
}
and when I want to use them, just use hostIdDeferred.await() to get the value. If I'm using Dispatchers.IO scope to run code inside new children coroutines, why coroutineScope is necessary? Is this the correct way, specifying a scope to the new coroutine child and then using coroutineScope to have a deferred val?
question 4.2: source 2 val resultOne = Async(Dispatchers.IO) { function1() } Intellij wasn't able to recognize/import any Async expression. How can I use this one and how it differs from previous one?
I'm open to improve and clarify any point on this question

I'll try to answer some of your questions:
q2: No, nothing wrong with it. Suspend methods can propagate all the way back to a controller. If your controllers are reactive, i.e. if you use RSocket with org.springframework.messaging.handler.annotation.MessageMapping, then even even controller methods can be suspend.
q3: right, but each method is still your source code is much simpler
q4.2: I wouldn't consider that website as a trustworthy source. There is an official documentation with examples: async

Related

Scala Dynamic Variable problem with Akka-Http asynchronous requests

My application is using Akka-Http to handle requests. I would like to somehow pass incoming extracted request context (fe. token) from routes down to other methods calls without explicitly passing them (because that would require modyfing a lot of code).
I tried using Dynamic Variable to handle this but it seems to not work as intended.
Example how I used and tested this:
object holding Dynamic Variable instance:
object TestDynamicContext {
val dynamicContext = new DynamicVariable[String]("")
}
routes wrapper for extracting and setting request context (token)
private def wrapper: Directive0 = {
Directive { routes => ctx =>
val newValue = UUID.randomUUID().toString
TestDynamicContext.dynamicContext.withValue(newValue) {
routes(())(ctx)
}
}
I expected to all calls of TestDynamicContext.dynamicContext.value for single request under my wrapper to return same value defined in said wrapper but thats not the case. I verified this by generating for each request separate UUID and passing it explicitly down the method calls - but for single request TestDynamicContext.dynamicContext.value sometimes returns different values.
I think its worth mentioning that some operations underneath use Futures and I though that this may be the issue but solution proposed in this thread did not solve this for me: https://stackoverflow.com/a/49256600/16511727.
If somebody has any suggestions how to handle this (not necessarily using Dynamic Variable) I would be very grateful.

How should I get this value through DDD to async code in Akka HTTP

I'm trying to write an Akka HTTP webservice using domain-driven design but I'm struggling to pass technical data received by the webservice to the code doing the work inside a Future, namely a correlationId sent by the client to my webservice.
My understanding of DDD is that as a choice of implementation, the correlationId shouldn't appear in the domain:
package domain
trait MyRepository {
def startWork(): Future[Unit]
}
To make it available to my implementation code without it being a parameter of the method, I'm thinking of using thread-local storage like org.slf4j.MDC or a ThreadLocal. However, I don't know if that would work or if several calls to the webservice would be handled by the same thread and overwrite the value.
Here is the implementation:
package infra
class MyRepository(implicit executor: ExecutionContextExecutor) extends domain.MyRepository {
override def startWork(): Future[Unit] = {
Future {
val correlationId = ??? // MDC.get("correlationId") ?
log(s"The correlationId is $correlationId")
}
}
}
And the route in my webservice:
val repo = new infra.MyRepository()
val route = path("my" / "path") {
post {
parameter('correlationId) { correlationId =>
??? // MDC.put("correlationId", correlationId) ?
onComplete(repo.startWork()) {
complete(HttpResponse(StatusCodes.OK))
}
}
}
}
My question is twofold:
Is my general design sound and good DDD?
Would using org.slf4j.MDC or a ThreadLocal work or is there a better / more Akka-friendly way to implement it?
Thread-locals (including MDC, though a Lightbend subscription includes tooling to propagate the MDC alongside messages and futures) in Akka are generally a poor idea because it's generally not guaranteed that a given task (a Future in this case, or the actor handling a sent message) will execute on the same thread as the thread that requested the task (and in the specific case where that task is performing [likely-blocking] interactions with an external service/DB (implied by the use of Future {}), you pretty much don't want that to happen). Further, even if the task ends up executing on the same thread that requested the task, it's somewhat unlikely that no other task which could have mutated the MDC/thread-local would've executed in the meantime.
I myself don't see a problem with passing the correlation ID as an argument to startWork: you've already effectively exposed it by passing it through the HTTP endpoint.

Vertx Web: How to split and organize routes across multiple files?

So far I'm really loving Vertx. The documentation is great, and the cross-language support is amazing.
However, the examples and documentation for my specific problem all seem to be out of date. I guess the API has changed a bit since 3.4.x (I'm currently using 3.9.1 with Scala 2.13.1.
I'd like to be able to split my routes among multiple files for the purpose of keeping things organized. For example, I'd like to have a UserRoutes file, and make a separate file for TodoRoutes, and both of those files can be used in my ServerVerticle.
The only way I've found to do this is basically:
UserRoutes:
object UserRoutes {
def createUser(context: RoutingContext): Unit = {
// do work
}
def login(context: RoutingContext): Unit = {
// do work
}
}
ServerVerticle:
class ServerVerticle(vertx: Vertx) extends AbstractVerticle {
override def start(): Unit = {
val router: Router = Router.router(vertx)
router.post("/user/new").handle(UserRoutes.createUser)
router.post("/user/login").handle(UserRoutes.login)
....
}
}
What I would really like to do instead:
object UserRoutes {
// somehow get a reference to `router` or create a new one
router.post("/user/new", (context: RoutingContext) => {
// do work
})
router.post("/user/login", (context: RoutingContext) => {
// do work
})
}
The reason I'd prefer this is because then it is easier to see exactly what is being done in UserRoutes, such as what path is being used, what parameters are required, etc.
I tried taking a similar approach to this example application, but apparently that's not really possible with the Vertx API as it exists in 3.9?
What is the best way to do this? What am I missing something? How do large REST APIs break up their routes?
I suppose one such way to do this would be something like the following:
UserRoutes
class UserRoutes(vertx: Vertx) {
val router: Router = {
val router = Router.router(vertx)
router.get("/users/login").handler(context => {
// do work
})
router
}
}
And then in the ServerVerticle:
...
server
.requestHandler(new UserVerticle(vertx).router)
.requestHandler(new TodoVerticle(vertx).router)
.listen(...)
This breaks stuff up nicely, but I still need to figure out a decent way to avoid having to repeats the cors options and stuff in each ___Routes file. There are plenty of way to do this of course, but the question remain: is this the right approach?
Further, I could really mix in some parts of the approach outlined in the initial question. The UserRoutes class could still have the createUser() method, and I could simply use this in the apply() call or somewhere else.
Sub-routers is another approach but there are still some issues with this.
It would also be nice if each ___Routes file could create it's own Verticle. If each set of Routes was running on it's own thread this could speed things up quite nicely.
Truth be told... as always in Scala there are a plethora of ways to tackle this. But which is the best, when we want:
Logical organization
Utilize the strengths of Vertx
Sub-verticles maybe?
Avoid shared state
I need guidance! There's so many options I don't know where to start.
EDIT:
Maybe it's best to avoid assigning each group of routes to a Verticle, and letting vertx do it's thing?

download a file with play web api (async)

I am trying to download a file using play api framework. Since all the data access layer has already been implemented with Futures I would like to get download to work with async action as well. However, the following piece of code does not work. And by not working I mean that the file sent to the client is not the same as the file on server.
val sourcePath = "/tmp/sample.pdf"
def downloadAsync = Action.async {
Future.successful(Ok.sendFile(new java.io.File(sourcePath)))
}
However, this piece works:
def download = Action {
Ok.sendFile(new java.io.File(sourcePath))
}
Any suggestion on how I can get the async method to work?
You actually don't need to use Action.async here, since Ok.sendFile is non-blocking already. From the docs:
Play actions are asynchronous by default. For instance, in the controller code below, the { Ok(...) } part of the code is not the method body of the controller. It is an anonymous function that is being passed to the Action object’s apply method, which creates an object of type Action. Internally, the anonymous function that you wrote will be called and its result will be enclosed in a Future.
def echo = Action { request =>
Ok("Got request [" + request + "]")
}
Note: Both Action.apply and Action.async create Action objects that are handled internally in the same way. There is a single kind of Action, which is asynchronous, and not two kinds (a synchronous one and an asynchronous one). The .async builder is just a facility to simplify creating actions based on APIs that return a Future, which makes it easier to write non-blocking code.
In other words, at this specific case, don't worry about wrapping your Result into a Future and just return Ok.sendFile.
Finally, both versions works as expected to me (the file was properly delivered). Maybe you are having another problem not related to how you have declared your actions.

How can I perform session based logging in Play Framework

We are currently using the Play Framework and we are using the standard logging mechanism. We have implemented a implicit context to support passing username and session id to all service methods. We want to implement logging so that it is session based. This requires implementing our own logger. This works for our own logs but how do we do the same for basic exception handling and logs as a result. Maybe there is a better way to capture this then with implicits or how can we override the exception handling logging. Essentially, we want to get as many log messages to be associated to the session.
It depends if you are doing reactive style development or standard synchronous development:
If standard synchronous development (i.e. no futures, 1 thread per request) - then I'd recommend you just use MDC, which adds values onto Threadlocal for logging. You can then customise the output in logback / log4j. When you get the username / session (possibly in a Filter or in your controller), you can then set the values there and then and you do not need to pass them around with implicits.
If you are doing reactive development you have a couple options:
You can still use MDC, except you'd have to use a custom Execution Context that effectively copies the MDC values to the thread, since each request could in theory be handled by multiple threads. (as described here: http://code.hootsuite.com/logging-contextual-info-in-an-asynchronous-scala-application/)
The alternative is the solution which I tend to use (and close to what you have now): You could make a class which represents MyAppRequest. Set the username, session info, and anything else, on that. You can continue to pass it around as an implicit. However, instead of using Action.async, you make your own MyAction class which an be used like below
myAction.async { implicit myRequest => //some code }
Inside the myAction, you'd have to catch all Exceptions and deal with future failures, and do the error handling manually instead of relying on the ErrorHandler. I often inject myAction into my Controllers and put common filter functionality in it.
The down side of this is, it is just a manual method. Also I've made MyAppRequest hold a Map of loggable values which can be set anywhere, which means it had to be a mutable map. Also, sometimes you need to make more than one myAction.async. The pro is, it is quite explicit and in your control without too much ExecutionContext/ThreadLocal magic.
Here is some very rough sample code as a starter, for the manual solution:
def logErrorAndRethrow(myrequest:MyRequest, x:Throwable): Nothing = {
//log your error here in the format you like
throw x //you can do this or handle errors how you like
}
class MyRequest {
val attr : mutable.Map[String, String] = new mutable.HashMap[String, String]()
}
//make this a util to inject, or move it into a common parent controller
def myAsync(block: MyRequest => Future[Result] ): Action[AnyContent] = {
val myRequest = new MyRequest()
try {
Action.async(
block(myRequest).recover { case cause => logErrorAndRethrow(myRequest, cause) }
)
} catch {
case x:Throwable =>
logErrorAndRethrow(myRequest, x)
}
}
//the method your Route file refers to
def getStuff = myAsync { request:MyRequest =>
//execute your code here, passing around request as an implicit
Future.successful(Results.Ok)
}