使用Akka处理SOAP消息

时间:2012-09-25 13:13:14

标签: http scala servlets akka

我正在为我的雇主构建一个小工具,并尝试使用Akka 2 + Scala实现它。

我正在接口的系统之一有一个SOAP api,它有一个有趣的实现:

----请求-------

客户----请求---->服务器

客户< --- Req Ack -----服务器

----响应------

客户端< ---响应----服务器

客户端---- Resp Ack ---->服务器

通过req-ack发送的任务ID来跟踪请求。

我的问题是SO社区,任何有akka经验的人都有以下几点:

  • 对于这种特定情况,使用akka处理http消息的理想方法是什么?我已经看过Akka-Mist的例子,看起来已经停止了支持play-mini,然后是akka-camel,我似乎无法找到该库作为akka 2.0.3的一部分分配,所以我对我应该采取什么方法感到困惑。是否有推荐的方法将servlet的行为封装在akka actor中?

提前谢谢大家。

1 个答案:

答案 0 :(得分:3)

你的问题非常开放,所以我会对你的要求作出一些假设。

请求假设:某些事件会产生大量请求。

创建一个具有包装async-http-client(https://github.com/sonatype/async-http-client)的actor的路由器。一旦async-http-client完成请求,它就会将具有Req Ack中包含的ID的消息发送给协调actor。协调参与者将聚合ID。

以下主要是伪代码,但它足够接近真正的API,你应该能够找出丢失的部分。

case class Request(url:String)
case class IDReceived(id:String)

case class RequestingActor extends Actor {

    override def receive = {
        case Request(url) => {
            //set up the async client and run the request
            //since it's async the client will not block and this actor can continue making generating more requests
        }
    }
}


class AsyncHttpClientResponseHandler(aggregationActor:ActorRef) extends SomeAsyncClientHandler {

    //Override the necessary Handler methods.

    override def onComplete = {
        aggregationActor ! IDReceived(//get the id from the response)
    }
}

class SomeEventHandlerClass { 

    val requestRouter = actorSystem.actorOf(Props[RequestingActor].withRouter(FromConfig(//maybe you've configured a round-robin router)), requestRouterName)

    def onEvent(url:String) {
        requestRouter ! Request(url)
    }

}

case class AggregationActor extends Actor {

    val idStorage = //some form of storage, maybe a Map if other information about the task ID needs to be stored as well.  Map(id -> other information)

    override def receive = {
        case IDReceived(id) => //add the ID to idStorage
    }
}

响应假设:您需要对响应中包含的数据执行某些操作,然后将ID标记为完成。 HTTP前端只需要处理这一组消息。

不要试图找到一个使用Akka集成的框架,而是使用一个简单的HTTP前端,它将消息发送到您创建的Akka网络中。我无法想象使用play-mini获得的任何优势,我认为它会模糊描述工作分离和控制的一些线条。情况并非总是如此,但鉴于您的问题缺乏要求,我没有其他任何依据我的意见。

case class ResponseHandlingActor extends Actor {

    val aggregationActor = actorSystem.actorFor(//the name of the aggregation router within the Actor System)

    override def receive = {
        case Response(data) => {
            //do something with the data.  If the data manipulation is blocking or long running it may warrant its own network of actors.
            aggregationActor ! ResponseReceived(//get the id from the response)
        }
    }
}

class ScalatraFrontEnd() extends ScalatraServlet {

    val responseRouter = actorSystem.actorOf(Props[RequestingActor].withRouter(FromConfig(//maybe you've configured a round-robin router)), requestRouterName)

    post("/response") {
        responseRouter ! Response(//data from the response)
    }

}

创建一个与此类似的系统可以很好地分离关注点,使得很容易推断出处理的位置,以及扩展系统或扩展系统的充足空间。