spray, scala : change the timeout - scala

I want to change the timeout in a spray application, but what is the simplest way to achieve this? I saw some examples on github but they are rather complicated.
thanks.
I tried this :
class MyServiceActor extends Actor with MyService {
sender ! SetRequestTimeout(scala.concurrent.duration.Duration(120,"second"))
sender ! spray.io.ConnectionTimeouts.SetIdleTimeout(scala.concurrent.duration.Duration(120,"second"))
// the HttpService trait defines only one abstract member, which
// connects the services environment to the enclosing actor or test
def actorRefFactory = context
// this actor only runs our route, but you could add
// other things here, like request stream processing
// or timeout handling
def receive = runRoute( myRoute )
}
but the timeout seems to stay at ~5 seconds.

you should be able to configure the timeout using the timeout configuration value for the underlying spray can server
spray.can.server {
request-timeout = 2s
}

Related

Get context from Main Actor in Akka

I'm attempting to shoot fire off a POST request like the one in the Akka docs showed here. http://doc.akka.io/docs/akka-http/current/scala/http/client-side/request-level.html#request-level-api
However, I'm trying to do it as inside of another defined class. If I try to add in anything that requires the Actor context like val http = HTTP(context.system) I get an error. How can I pass in the context into the class I'm trying to make the POST request from?
trait CustomerProfilesComponent {
def customerProfileManager: CustomerService.Async
}
object DefaultCustomerProfiles {
private case class ProfileUpdateData(path: Seq[String], data: JsObject, metadata: JsObject)
}
trait DefaultCustomerProfiles extends CustomerProfilesComponent {
self: DatabaseComponent with SourceVersionComponent with ExecutionContextComponent =>
import DefaultCustomerProfiles._
lazy val customerProfileManager = new CustomerService.Async {
import db.api._
import AvroConverter._
override def getVersion : Future[AvroVersion] = {
Future.successful(toAvro(sourceVersion))
}
}
What you need is actually an actor system. Posting from the akka-http docs:
The request-level API is implemented on top of a connection pool that is shared inside the ActorSystem.
There are two usage scenarios for the request API:
use it within an actor - when you can get the actor system via the actor context (like you have tried, but since you are not inside an actor, you don't have an actor context available)
use it outside an actor (your case) - when you can get the actor system by providing it as an dependency (either via class/method params or implicit params)
I hope this is helpful.

Akka cluster singleton as scheduler

I am running Play with an Akka cluster.
I need an "Singleton Scheduler" to execute some tasks every hour.
What I found out so far is, that I should use ClusterSinglegonManager.
But I am not sure how my Actor must look like.
In my opinion, I wouldn't need a "receive" Method.
That is, how I instatiate my Singleton:
system.actorOf(
ClusterSingletonManager.props(
singletonProps = MySingletonActor.props(configuration),
terminationMessage = PoisonPill,
settings = ClusterSingletonManagerSettings(system)),
name = "mysingletonactor")
That would fit:
object MySingletonActor {
def props(configuration: Configuration): Props = Props(new MySingletonActor(configuration))
}
class MySingletonActor(configuration: Configuration) extends Actor with ActorLogging {
context.system.scheduler.schedule(2 seconds, 2 seconds)(println("Hallo Welt"))
def receive = ???
}
But of course it raises exceptions, because of the missing implementation of the receive method. But it works.
What is the best way to go here?
It feels awkward to just schedule a "Tick" and handle the Tick in the receive Method...
class MySingletonActor(configuration: Configuration) extends Actor with ActorLogging {
case object Tick
context.system.scheduler.schedule(2 seconds, 2 seconds, self, Tick)
def receive = { case Tick => println("Hallo Welt") }
}
Is there any kind of a Singleton Scheduler in Akka?
Instead of writing ??? as receive method, you can use Actor.emptyBehavior to not raise an Exception. This is a Receive-expression that matches no messages at all, ever.

How to manage HTTP requests in Akka?

I'm using Spray in my application and from the examples I've see on Github it looks like people handle HTTP requests in Akka by passing the HTTPContext object around to all the actors and calling onComplete { } on the Future in the last actor.
Is sending the context deep down in the application really a good idea ? This way every event object will have a context parameter.
How do we handle HTTP requests & response properly in Akka? I've read this article but I would like to know people's thoughts who run Akka in production on the right way of achieving this.
I prefer to use the ask pattern in the Spray service, and the onSuccess directive, e.g.:
trait MyService extends HttpService {
def worker: ActorRef
implicit def timeout:Timeout
implicit def ec:ExecutionContext
def askWorker: Future[String] = (worker ? "Hello").mapTo[String]
def myRoute = path("/") {
get {
onSuccess(askWorker){
case str => complete(str)
}
}
}
}
Then a concrete actor such as:
class ServiceActor extends MyService with Actor {
implicit val ec = context.system
implicit val timeout = Timeout(3 seconds)
val worker = context.actorOf(Props[WorkerActor])
override def actorRefFactory = context.system
def receive = runRoute(myRoute)
}
I like this pattern rather than passing the request context around since it means that the other actors don't have to have any concept of Http. The service could be completely replaced with a different protocol. In this example the worker actor is can be something like:
class WorkerActor extends Actor {
def receive = {
case "Hello" => sender() ! "Hello World"
}
}

Akka IO and TestActorRef

If I need to write an integration test involving HTTP request via spray-can, how can I make sure that spray-can is using CallingThreadDispatcher?
Currently the following actor will print None
class Processor extends Actor {
override def receive = {
case Msg(n) =>
val response = (IO(Http) ? HttpRequest(GET, Uri("http://www.google.com"))).mapTo[HttpResponse]
println(response.value)
}
}
How can I make sure that the request is being performed on the same thread as the test (resulting in a synchronous request)?
It seems like strange way to do integration internal-testing as you don't mock the "Google", so is more like integration external-testing and synchronous TestActorRef doesn't much fit here. The requirement to control threads inside spray is also pretty tricky. However, if you really need that for http-request - it's possible. In general case, you have to setup several dispatchers in your application.conf:
"manager-dispatcher" (from Http.scala) to dispatch your IO(Http) ? req
"host-connector-dispatcher" to use it by HttpHostConnector(or ProxyHttpHostConnector) which actually dispatch your request
"settings-group-dispatcher" for Http.Connect
They all are decribed in Configuration Section of spray documentation. And they all are pointing to "akka.actor.default-dispatcher" (see Dispatchers), so you can change all of them by changing this one.
The problem here is that calling thread is not guaranteed to be your thread actually, so it will NOT help much with your tests. Just imagine if some of actors registers some handler, responding to your message:
//somewhere in spray...
case r#Request => registerHandler(() => {
...
sender ! response
})
The response may be sent from another thread, so response.value may still be None in current. Actually, the response will be sent from the listening thread of underlying socket library, indepently from your test's thread. Simply saying, request may be sent in one (your) thread, but the response is received in another.
If you really really need to block here, I would recommend you to move such code samples (like IO(Http) ? HttpRequest) out and mock them in any convinient way inside your tests. Smtng like that:
trait AskGoogle {
def okeyGoogle = IO(Http) ? HttpRequest(GET, Uri("http://www.google.com"))).mapTo[HttpResponse]
}
trait AskGoogleMock extends AskGoogle {
def okeyGoogle = Await.result(super.okeyGoogle, timeout)
}
class Processor extends Actor with AskGoogle {
override def receive = {
case Msg(n) =>
val response = okeyGoogle
println(response.value)
}
}
val realActor = system.actorOf(Props[Processor])
val mockedActor = TestActorRef[Processor with AskGoogleMock]
By the way, you can mock IO(HTTP) with another TestActorRef to the custom actor, which will do the outside requests for you - it should require minimal code changes if you have a big project.

How to pass a class as a parameter for instantiation in Scala

I am trying to refactor an Akka application from a single tier to multi-tier structure with akka clustering (http://doc.akka.io/docs/akka/2.3.9/scala/cluster-usage.html). Within the application are some actors that have a parameterized default constructor, e.g.
class MyActor(someParam: boolean = true) extends Actor {
def receive = { /* message handling here... */ }
}
I am now trying to create a generic router actor that will route to a node with a specific node. The cluster configuration is working based of the example on the akka site, and I can create a router in 1 role that routes to the actor in another role:
class MyActorProxy extends Actor {
val workerRouter = context.actorOf(FromConfig.props(Props(classOf[MyActor]), name = "workerRouter")
def receive = {
case msg: Any =>
val currentSender = sender()
workerRouter.tell(msg, currentSender)
}
}
This method works as needed. However, I need to go and create a handful of proxy classes with the same functionality, and it's painful. I'm trying to make it work better, and limited scala experience is making it difficult. Here's what I am trying to do:
abstract class RouterProxy[T <: Actor](routerPath: String) extends Actor {
val router = context.actorOf(FromConfig.props(Props(classOf[T])),name=routerPath)
def receive = {
case msg: Any => {
val currentSender = sender()
router.tell(msg,currentSender)
}
}
}
class MyActorProxy extends RouterProxy[MyActor](routerPath = "myActorRouter")
Have come up with this by reading through some scala docs and through stackoverflow, but can't seem to get it right - this approach doesn't let me create the props for the actor. I've seen How to instantiate an instance of type represented by type parameter in Scala and I think that the type information is being lost (type erasure).
How would I go about passing an actor class to the router proxy to allow for router initialization?
This is the error I get during compilation, while initializing the router:
class type required but T found
edit
Background for using a generic proxy router
The reason for this approach is to refactor the application for both single tier and multi-tier architecture. When running multi-tier, I want to skip initializing any "heavy" actors. Given I have the following config on a frontend node:
akka.actor.deployment {
/workerRouter {
routee.paths = ["/user/myActor"]
cluster.use-role = backend
}
}
akka.cluster.roles = [frontend]
and the backend node has roles of [backend], then when I start up frontend nodes, MyActor will not be initialized. MyActor is an example of 1 of many actors that are supervisors / managers. Each 1 of them might initialize a few other actors in turn (sometimes with routers). What I'm trying to do is refactor the application so I can run lightweight frontend nodes in a different tier to resource heavy backend nodes if I need to, but also still have the ability to run all on a single node. By this approach, I can add in initialization for heavy managers into my application bootstrap and add a role and it becomes a multifunctional app without needing recoding.
edit 2
I am able to get the application to work as expected if the class constructor doesn't take any arguments.
MyActor extends Actor { /* ... */ }
And then in my abstract class:
abstract class RouterProxy[T <: Actor](routerPath: String) extends Actor {
val router = context.actorOf(FromConfig.props(Props[T]),name = routerPath)
}
Props[MyActor] works fine for a parameterless actor, but Props(classOf[T]) looses the type.
You don't actually have to define another class for the router, you can do it all through your configuration file:
val myActorRouter = system.actorOf(Props[MyActor]
.withRouter(FromConfig())
,"workerRouter")
Where "workerRouter" is defined in your application.conf file like this:
akka.actor.deployment {
/workerRouter {
router = round-robin
nr-of-instances = 5
}
}
You can also configure it all through code if you have a pretty simple configuration:
val myActorRouter = system.actorOf(Props[MyActor].withRouter(
RoundRobinRouter(nrOfInstances = 5)))
Either way you end up with myActorRouter as an actor ref you can send messages to. In the background the Akka system has created a pool of MyActor actors and forwards the messages to them. The router takes itself out of the response so you don't need to spoof the sender like you've done: when a routee sends a message to sender it goes directly back to the actor that sent the message to the router.