I am trying to count rejects that were returned by RejectionHandler
I guess the way I doing this now is not the best one, or even incorrect. I am just trying to invoke the incremental method in my database, in each of the handled cases.
implicit def rejectionHandler: RejectionHandler =
RejectionHandler.newBuilder()
.handle {
case MissingCookieRejection(cookieName) =>
requestInfoEntry.incrementRjectedNum
complete(HttpResponse(BadRequest, entity = "No cookies, no service!!!"))
}
.handle {
case AuthorizationFailedRejection =>
requestInfoEntry.incrementRjectedNum
complete((Forbidden, "You're out of your depth!"))
}
.handle {
case ValidationRejection(msg, _) =>
requestInfoEntry.incrementRjectedNum
complete((InternalServerError, "That wasn't valid! " + msg))
}
.handleAll[MethodRejection] { methodRejections =>
requestInfoEntry.incrementRjectedNum//todo sideeffect ??
val names = methodRejections.map(_.supported.name)
complete((MethodNotAllowed, s"Can't do that! Supported: ${names mkString " or "}!"))
}
.handleNotFound {
requestInfoEntry.incrementRjectedNum
complete((NotFound, "Not here bldghad!"))
}
.result()
While I "visit my unfound page", Akka HTTP returns me a right response: "Not here bldghad!" every time I refresh browser on not existed web-page. But when I check my database, I see the only one increment. Can I do this way as I do at all? (I need to count successes too)
PS Maybe I need to work with status codes and do not use side effects. But what is the best place where I can do it? I have a lot of controllers and do not want to intercept this in every controller)
Can I globally intercept responses somewhere?
I've done it this way, hope it would be useful
def rejectionHandlerWithCounter: RejectionHandler = { (rejections: Seq[Rejection]) =>
requestInfoEntry.incrementRjectedNum
Some(complete((StatusCodes.Forbidden)))
}
Related
I'm kinda new to akka typed and I was trying to send a message which requires an answer within a given time.
I found the request-response pattern with ask which seemed interesting but is there a way to implement it inside of an already defined Behaviours.receive?
Here the idea is to call nextPlayerTurn each time a player answers or after a timeout
override def refereeTurn(): Behavior[Msg] = Behaviors.receive {
case (_, msg: GuessMsg) =>
if(currentPlayer.isDefined && currentPlayer.get == msg.getSender) {
controller ! msg
} else {
println("Player tried to guess after Timeout")
}
Behaviors.same
case (context, msg: ReceivedResponseMsg) =>
if(currentPlayer.isDefined && currentPlayer.get == msg.getSender)
nextPlayerTurn(context)
Behaviors.same
...
}
...
/**
* Tells to a player to start his turn and sets a timer that defines time in which a player has to make a guess.
* If such guess isn't made, sends that user an end turn message, fails the promise of his turn and allows next
* player to play his turn
*/
override def nextPlayerTurn(ctx: ActorContext[Msg]): Unit = {
implicit val timeout: Timeout = Timeout.timeout
currentPlayer = Option(turnManager.nextPlayer)
ctx.ask[Msg,Msg](currentPlayer.get, ref => YourTurnMsg(ref)) {
case Success(msg: GuessMsg) => println("\n SUCCESS"); msg
case Failure(_) => println(currentPlayer.get +" didn't guess in time"); TurnEnd(currentPlayer.get)
case _ => TurnEnd(currentPlayer.get)
}
}
In this case after the YourTurnMsg is sent the player is supposed to respond with a GuessMsg which stops the timer, this never happens due to the case matching inside refereeTurn Begaviour being executed instead of the Success (which instead always gives a Failure after the Timeout).
Did i get the wrong idea about the ask patter and should just make a new Behaviour with a timer?
If you want to use the ask pattern then the code that handles the result needs to send a message to the main actor rather than trying to do any processing directly. You can send a different message based on the result or just send the raw result and process it in the actor, but you must not do anything that depends on actor state in that code because it could be run on a different thread.
But ask is not cheap so in this case it seems better to just set a timer and see which message comes back first.
Coming from a Java background, I have been trying to teach myself Scala for some time now. As part of that, I am doing a small pet project that exposes a HTTP endpoint that saves the registration numberof a vehicle against the owner and returns the status.
To give more context, I am using Slick as FRM which performs DB operations asynchronously and returns a Future.
Based on the output of this Future, I want to set the status variable to return back to the client.
Here, is the code
def addVehicleOwner(vehicle: Vehicle): String = {
var status = ""
val addFuture = db.run((vehicles returning vehicles.map(_.id)) += vehicle)
addFuture onComplete {
case Success(id) => {
BotLogger.info(LOGTAG, s"Vehicle registered at $id ")
status = String.format("Registration number - '%s' mapped to owner '%s' successfully", vehicle.registration,
vehicle.owner)
println(s"status inside success $status") //--------- (1)
}
case Failure(e: SQLException) if e.getMessage.contains("SQLITE_CONSTRAINT") => {
status = updateVehicleOwner(vehicle)
BotLogger.info(LOGTAG, s"Updated owner='${vehicle.owner}' for '${vehicle.registration}'")
}
case Failure(e) => {
BotLogger.error(LOGTAG, e)
status = "Sorry, unable to add now!"
}
}
exec(addFuture)
println(s"Status=$status") //--------- (2)
status
}
// Helper method for running a query in this example file:
def exec[T](sqlFuture: Future[T]):T = Await.result(sqlFuture, 1 seconds)
This was fairly simple in Java. With Scala, I am facing the following problems:
The expected value gets printed at (1), but (2) always prints empty string and same is what method returns. Can someone explain why?
I even tried marking the var status as #volatile var status, it still evaluates to empty string.
I know, that the above is not the functional way of doing things as I am muting state. What is the clean way of writing code for such cases.
Almost all the examples I could find described how to map the result of Success or handle Failure by doing a println. I want to do more than that.
What are some good references of small projects that I can refer to? Specially, that follow TDD.
Instead of relying on status to complete inside the closure, you can recover over the Future[T] which handle the exception if they occur, and always returns the result you want. This is taking advantage of the nature of expressions in Scala:
val addFuture =
db.run((vehicles returning vehicles.map(_.id)) += vehicle)
.recover {
case e: SQLException if e.getMessage.contains("SQLITE_CONSTRAINT") => {
val status = updateVehicleOwner(vehicle)
BotLogger.info(
LOGTAG,
s"Updated owner='${vehicle.owner}' for '${vehicle.registration}'"
)
status
}
case e => {
BotLogger.error(LOGTAG, e)
val status = "Sorry, unable to add now!"
status
}
}
val result: String = exec(addFuture)
println(s"Status = $result")
result
Note that Await.result should not be used in any production environment as it synchronously blocks on the Future, which is exactly the opposite of what you actually want. If you're already using a Future to delegate work, you want it to complete asynchronously. I'm assuming your exec method was simply for testing purposes.
I am building some custom directives with Spray and I find a problem:
When a route is rejected I thought that it was immediately completed with a rejection. However it is not and it tries to complete the inner route. For example, in this code:
path("users") {
post {
entity(as[User]){
user =>
directive_always_reject(){
println("Hello")
complete(200, "Hello")
}
}
}
}
The "hello" is always printed, even if the directive is rejected.
I always thought that when a route is rejected it does not continue to inner routes (or at least is how I understand it)
Did I misunderstand something with Spray or there is a bug somewhere in my code?
Thanks you!
[UPDATE 1]
An implementation of directive_always_reject() could be:
def directive_always_reject[T]() : Directive0 = {
reject(
new ValidationRejection("Some error")
)
}
[UPDATE 2]
I see that a solution could be put the println inside the complete function.
path("users") {
post {
entity(as[User]){
user =>
directive_always_reject(){
complete {
println("Hello")
"Hello"
}
}
}
}
}
However this solution does not apply to me because in my real code I pass the RequestContext to another actor who is the one that completes the request.
I was hoping someone can briefly go over the various ways of consuming a service (this one just returns a string, normally it would be JSON but I just want to understand the concepts here).
My service:
def ping = Action {
Ok("pong")
}
Now in my Play (2.3.x) application, I want to call my client and display the response.
When working with Futures, I want to display the value.
I am a bit confused, what are all the ways I could call this method i.e. there are some ways I see that use Success/Failure,
val futureResponse: Future[String] = WS.url(url + "/ping").get().map { response =>
response.body
}
var resp = ""
futureResponse.onComplete {
case Success(str) => {
Logger.trace(s"future success $str")
resp = str
}
case Failure(ex) => {
Logger.trace(s"future failed")
resp = ex.toString
}
}
Ok(resp)
I can see the trace in STDOUT for success/failure, but my controller action just returns "" to my browser.
I understand that this is because it returns a FUTURE and my action finishes before the future returns.
How can I force it to wait?
What options do I have with error handling?
If you really want to block until feature is completed look at the Future.ready() and Future.result() methods. But you shouldn't.
The point about Future is that you can tell it how to use the result once it arrived, and then go on, no blocks required.
Future can be the result of an Action, in this case framework takes care of it:
def index = Action.async {
WS.url(url + "/ping").get()
.map(response => Ok("Got result: " + response.body))
}
Look at the documentation, it describes the topic very well.
As for the error-handling, you can use Future.recover() method. You should tell it what to return in case of error and it gives you new Future that you should return from your action.
def index = Action.async {
WS.url(url + "/ping").get()
.map(response => Ok("Got result: " + response.body))
.recover{ case e: Exception => InternalServerError(e.getMessage) }
}
So the basic way you consume service is to get result Future, transform it in the way you want by using monadic methods(the methods that return new transformed Future, like map, recover, etc..) and return it as a result of an Action.
You may want to look at Play 2.2 -Scala - How to chain Futures in Controller Action and Dealing with failed futures questions.
Helo,
at the beginning i wold like to apologize for my english :)
akka=2.3.6
spray=1.3.2
scalatest=2.2.1
I encountered strange behavior of teting routes, which asks actors in handleWith directive,
I've route with handleWith directive
pathPrefix("firstPath") {
pathEnd {
get(complete("Hello from this api")) ~
post(handleWith { (data: Data) =>{ println("receiving data")
(dataCalculator ? data).collect {
case Success(_) =>
Right(Created -> "")
case throwable: MyInternalValidatationException =>
Left(BadRequest -> s"""{"${throwable.subject}" : "${throwable.cause}"}""")
}
}})
}
}
and simple actor wchich always responds when receive object Data and has own receive block wrapped in LoggingReceive, so I should see logs when message is receiving by actor
and i test it using (I think simple code)
class SampleStarngeTest extends WordSpec with ThisAppTestBase with OneInstancePerTest
with routeTestingSugar {
val url = "/firstPath/"
implicit val routeTestTimeout = RouteTestTimeout(5 seconds)
def postTest(data: String) = Post(url).withJson(data) ~> routes
"posting" should {
"pass" when {
"data is valid and comes from the identified user" in {
postTest(correctData.copy(createdAt = System.currentTimeMillis()).asJson) ~> check {
print(entity)
status shouldBe Created
}
}
"report is valid and comes from the anonymous" in {
postTest(correctData.copy(createdAt = System.currentTimeMillis(), adid = "anonymous").asJson) ~> check {
status shouldBe Created
}
}
}
}
}
and behavior:
When I run either all tests in package (using Intellij Idea 14 Ultimate) or sbt test I encounter the same results
one execution -> all tests pass
and next one -> not all pass, this which not pass I can see:
1. fail becouse Request was neither completed nor rejected within X seconds ( X up tp 60)
2. system console output from route from line post(handleWith { (data: Data) =>{ println("receiving data"), so code in handleWith was executed
3. ask timeout exception from route code, but not always (among failed tests)
4. no logs from actor LoggingReceive, so actor hasn't chance to respond
5. when I rerun teststhe results are even different from the previous
Is there problem with threading? or test modules, thread blocking inside libraries? or sth else? I've no idea why it isn't work :(