1

I'd like to make a web request using the spray client out of an actor this web request requires a parameter which has to be part of the receiving message. In order to do this I created a case class like:

case class MessageWithParam(param: String)

The Actor looks like this:

import akka.actor.{Actor, ActorLogging}
import akka.util.Timeout
import spray.client.pipelining._
import spray.http.{FormData, HttpRequest, HttpResponse}

import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.{Failure, Success}
import scala.xml.XML

import org.example.MessageWithParam

class WebCall extends Actor with ActorLogging  {
  import context.dispatcher
  implicit val timeout: Timeout = Duration(5, SECONDS) // TODO Eliminate magic number
  val pipeline: HttpRequest => Future[HttpResponse] = sendReceive

  def receive = {
    case MessageWithParam(param) => {
      val sendingActor = sender()
      val data =  Seq("Param" -> param)
      val request = Post("http://my.server.com/request",FormData(data))

      pipeline(request) onComplete {
        case Success(httpResponse: HttpResponse) => {
          ...
        }
        case Failure(error) => {
          ...
        }
      }
    }
  }
}

My problem is, whenever the message is a string, e.g.:

 def receive = {
   case "Message" => {
     ...
 }

the service call is excecuted. But if I use a case class in order to be able to parametrise the message the web call goes in a timeout but (I checked it with wireshark ) not even a connection to the server is established.

Code that calls the Message:

import akka.actor.{ActorSystem, Props}
import akka.testkit.{DefaultTimeout, ImplicitSender, TestKit}
import org.example.WebCall
import org.example.MessgeWithParam
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
import scala.concurrent.duration._

class WebCallTest extends TestKit(ActorSystem("WebCallTest",
   ConfigFactory.parseString(TestConfig.config)))
   with DefaultTimeout with ImplicitSender
   with WordSpecLike with Matchers with BeforeAndAfterAll {

   val webCallRef = system.actorOf(Props(classOf[WebCall]))

   override def afterAll {
     shutdown()
   }

   "A WebCall" should {
     "Respond to a 'example' call with a 'success' message" in {
       within(5000 millis) {
         webCallRef ! MessgeWithParam("example")
         expectMsg("success")
       }
     } 
   } 
}

Am I in a different context when messages are case classes?

Thank you for any help

Regards Akira

Akira
  • 83
  • 5
  • Can you post the code that sends the message? – jrudolph Dec 02 '14 at 15:21
  • Try changing data to a `Map` instead of a `Seq`. `Map("Param" -> param)`. – Soumya Simanta Dec 02 '14 at 15:56
  • @jrudolph: Added the test in the original message – Akira Dec 02 '14 at 16:12
  • @Soumya Simanta: changing into a Map actually did not help – Akira Dec 02 '14 at 16:19
  • Can you try adding some logging statements (even println are fine for explorative debugging):1)inside the MessageWithParam branch of the receive 2) adding a default case to the receive (_ =>) and into it 3) inside both the success and failure branches of your pipeline completition ? Your code looks fine, we need to know better what path is executed. Timestamps in the logs would also be helpful. – Diego Martinoia Dec 02 '14 at 17:11
  • @DiegoMartinoia: It's weird. I started working at adding some logging code and now it works. But the reason of the failure is still unknown to me. Thank you so much for your kind help! (applies for everybody answering to this post!) – Akira Dec 03 '14 at 08:53
  • If it only works with logs then it's not working! If it really only works when logs are activated, it smells like somewhere you have a race condition! – Diego Martinoia Dec 03 '14 at 10:13

0 Answers0