gpt4 book ai didi

scala - 可以将路由完成 DSL 卸载到 akka-http 中的参与者吗?

转载 作者:行者123 更新时间:2023-12-01 11:21:01 25 4
gpt4 key购买 nike

我对 akka-http 的实现很感兴趣,但有一件事让我觉得是一种反模式,那就是为所有路由、参数解析、错误处理等创建 DSL。文档中给出的例子极其琐碎。然而,我在市场上看到了一个真实产品的路由,它是一个巨大的 10k 行文件,其中包含许多层次和路由中的大量业务逻辑。现实世界的系统必须处理用户传递错误参数、没有正确权限等问题,因此简单的 DSL 在现实生活中会迅速爆炸。对我来说,最佳解决方案是将路线完成交给 Actor ,每个 Actor 都有相同的 api,然后他们将完成路线所需的工作。这将分散逻辑并启用可维护的代码,但几个小时后我无法管理它。使用低级 API,我可以传递 HttpRequest 并以旧方式处理它,但这使我无法使用 DSL 中的大部分工具。那么有没有一种方法可以将一些东西传递给一个参与者,使其能够在那个时候继续 DSL,处理路由特定的东西? IE。我在谈论这样的事情:

  class MySlashHandler() extends Actor {
def receive = {
case ctxt: ContextOfSomeKind =>
decodeRequest {
// unmarshal with in-scope unmarshaller
entity(as[Order]) { order =>
sender ! "Order received"
}
context.stop(self)
}
}

val route =
pathEndOrSingleSlash {
get { ctxt =>
val actor = actorSystem.actorOf(Props(classOf[MySlashHandler]))
complete(actor ? ctxt)
}
}

当然,这甚至不会编译。尽管我尽了最大的努力,但我还没有找到 ContextOfSomeKind 的类型,也没有找到进入 actor 后如何重新进入 DSL 的方法。这可能是不可能的。如果不是,我认为我不喜欢 DSL,因为它鼓励我认为可怕的编程方法。那么低级 API 的唯一问题是访问实体编码器,但我宁愿这样做然后在单个源文件中制作一个大型应用程序。

最佳答案

卸载路由完成

直接回答您的问题:Route 只不过是一个函数。 The definition being :

type Route = (RequestContext) => Future[RouteResult]

因此,您可以简单地编写一个函数来执行您要查找的操作,例如将 RequestContext 发送给 Actor 并取回结果:

class MySlashHandler extends Actor {

val routeHandler = (_ : RequestContext) => complete("Actor Complete")

override def receive : Receive = {
case requestContext : RequestContext => routeHandler(requestContext) pipeTo sender
}
}

val actorRef : ActorRef = actorSystem actorOf (Props[MySlashHandler])

val route : Route =
(requestContext : RequestContext) => (actorRef ? requestContext).mapTo[RouteResult]

Actor 无法解决您的问题

您试图处理的问题是现实世界的复杂性以及在代码中对这种复杂性进行建模。我同意这是一个问题,但 Actor 不是您的解决方案。对于您寻求的设计解决方案,避免使用 Actors 有多种原因:

  1. compelling arguments against putting business logic inActors .
  2. Akka-http 在底层使用 akka-stream。 Akka 流在底层使用 Actors。因此,您正试图通过使用 Actors 来逃避基于可组合 Actors 的 DSL。水通常不是溺水者的解决方案......
  3. akka-http DSL 提供了大量编译时检查,一旦您恢复到 Actor 的非类型化 receive 方法,这些检查就会被冲走。你会得到更多的运行时错误,例如死信,通过使用 Actors。

路线组织

如前所述:Route 是一个简单的函数,是 scala 的构建 block 。仅仅因为您看到了一个草率的开发人员将所有逻辑保存在一个文件中的示例,并不意味着这是唯一的解决方案。

我可以在 main 方法中编写我所有的应用程序代码,但这并不能使其成为良好的函数式编程设计。同样,我可以在一个 for 循环中编写我所有的收集逻辑,但我通常使用 filter/map/reduce。

相同的组织原则适用于路线。从最基本的角度来看,您可以根据方法类型分解路由逻辑:

//GetLogic.scala
object GetLogic {
val getRoute = get {
complete("get received")
}
}

//PutLogic.scala
object PutLogic {
val putRoute = put {
complete("put received")
}
}

另一个常见的组织原则是将业务逻辑与路由逻辑分开:

object BusinessLogic {

type UserName = String
type UserId = String

//isolated business logic
val dbLookup(userId : UserId) : UserName = ???

val businessRoute = get {
entity(as[String]) { userId => complete(dbLookup(userId)) }
}
}

然后这些都可以在您的主要方法中组合:

val finalRoute : Route = 
GetLogic.getRoute ~ PutLogic.putRoute ~ BusinessLogic.businessRoute

路由 DSL 可能会产生误导,因为它有时看起来有点像魔法,但在它的下面只是普通的旧函数,scala 可以很好地组织和隔离这些函数...

关于scala - 可以将路由完成 DSL 卸载到 akka-http 中的参与者吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43173103/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com