我刚刚开始使用Akka Http(和Scala),并想知道是否有任何明确定义的模式来构建Akka代码。特别是,我正在寻找动态组合/聚合路由的结构模式。特别是,我正在寻找类似于以下伪代码的解决方案:
trait MyActor extends Actor {
val myRouter: ActorRef = context.actorOf(FromConfig.props(Props[MyWorker]), "Worker")
val myRoute = .... //route definition for this trait
}
trait MySecondActor extends Actor {
val mySecondRouter: ActorRef = context.actorOf(FromConfig.props(Props[MySecondWorker]), "SecondWorker")
val myRoute = .... //route definition for this trait
}
然后,在我的主服务器中混合使用特征来自动获取actor和路由:
class HttpServer extends SomeTrait with MyActor with MySecondActor {
.....
.....
}
上述模式存在一些明显的问题,包括:
new HttpServer()
实例化我正在寻找的是一种模式:
我在StackOverflow上遇到了以下两个,但是想知道是否有更好的方法和明确定义的模式:
谢谢!
答案 0 :(得分:5)
使用akka-http时,您通常不需要演员来实施路由。 Actor通常仅用于异步访问业务逻辑。让我举例说明如何使用预定义的路由构建代码。这是我从Heiko Seeberger学到的模式。
首先创建一个创建路线的对象:
object Api {
def route: Route = {
import import akka.http.scaladsl.server.Directives._
pathSingleSlash {
get {
complete(StatusCodes.OK)
}
}
}
}
如果您需要演员来访问您的业务逻辑,您可以将其作为参数传递给route
方法。在请求处理期间与actor交互时,请记住使用ask pattern。
比你创建一个创建你的Api的Root actor:
final class Root extends Actor with ActorLogging {
Http(context.system)
.bindAndHandle(Api.route, "0.0.0.0", 8000)
.pipeTo(self)
override def receive: Receive = {
case s: ServerBinding =>
log.info(s"Listening to ${s.localAddress}")
context.become(Actor.emptyBehavior)
case Status.Failure(t) =>
log.error(t, "Error binding to network interface")
context.stop(self)
}
}
最后,您需要一些主要方法来创建actor系统和Root actor:
object Main {
def main(args: Array[String]): Unit = {
val system = ActorSystem("user-api")
system.actorOf(Props(new Root))
Await.ready(system.whenTerminated, Duration.Inf)
}
}
所以这将是我对定义akka-http路由的最佳实践的看法。我的答案中没有涉及的是如何动态发现路由,但说实话,我在这里看不到用例。通常,您的系统应该有一些明确定义的端点。如果系统不知道它将在启动时服务哪些端点,用户将如何知道他们可以与哪些端点通信?