【问题标题】:Accessing Akka Actor context inside a mixin在 mixin 中访问 Akka Actor 上下文
【发布时间】:2017-07-18 12:38:25
【问题描述】:

我想定义一个可以与 Akka actor 混合的 trait,它会在某个有限的持续时间后安排接收超时。这是我想要做的草图......

trait BidderInActivityClearingSchedule[T <: Tradable, A <: Auction[T, A]]
    extends ClearingSchedule[T, A] {
  this: AuctionActor[T, A] =>

  context.setReceiveTimeout(timeout)  // can I call this here?

  def timeout: FiniteDuration

  override def receive: Receive = {
    case ReceiveTimeout =>
      val (clearedAuction, contracts) = auction.clear
      contracts.foreach(contract => settlementService ! contract)
      auction = clearedAuction
    case message => this.receive(message)
  }

}


class FancyAuctionActor[T <: Tradable](val timeout: FiniteDuration, ...)
    extends AuctionActor[T, FancyAuctionActor[T]]
    with BidderInActivityClearingSchedule[T, FancyAuctionActor[T]]

...但我不明白什么时候会调用context.setReceiveTimeout。当MyFancyAuctionActor 被调用时,它会作为构造函数的一部分被调用吗?还是会因为timeout 尚未定义而提前调用并因此引发某种错误。

【问题讨论】:

    标签: scala akka mixins akka-actor


    【解决方案1】:

    我建议使用 actor 的生命周期事件挂钩来控制您的日程安排的触发。如果您的 trait 像这样扩展一个 actor:

    trait AuctionActor[T, A] extends Actor
    trait BidderInActivityClearingSchedule[T, A] extends AuctionActor[T,A] 
    

    您将可以访问参与者的许多生命周期事件挂钩,例如 preStart()postStop() 等等。

    所以你可以轻松做到:

    trait BidderInActivityClearingSchedule[T, A] extends AuctionActor[T,A] {
      override def preStart() = {
        supre.preStart() // or call this after the below line if must.
        context.setReceiveTimeout(timeout)  // can I call this here?
      }    
    }
    

    更新

    如果你想实现一个可堆叠的 mixins 结构。你会做与上面类似的事情。

    //your AuctionActor is now a class as you wanted it
    class AuctionActor[T, A] extends Actor
    
    //Look below; the trait is extending a class! it's ok! this means you can 
    //only use this trait to extend an instance of AuctionActor class 
    trait BidderInActivityClearingSchedule[T, A] extends AuctionActor[T,A]{
      def timeout: FiniteDuration
    
      //take note of the weird "abstract override keyword! it's a thing!"
      abstract override def preStart() = {
        super.preStart()
        context.setReceiveTimeout(timeout)
      }
    }
    

    您可以将扩展类 AuctionActor 的任意多特征堆叠在一起。

    【讨论】:

    • 使用 Actor 生命周期钩子不是一个坏主意,但我不想扩展 Actor 我想将 trait 保留为 mixin。
    • 据我所知,可堆叠混入的最佳实践方法是让所有混入扩展基本特征。您实际上是在通过仅在您的情况下使用 self 类型注释来做同样的事情,您正在剥夺自己覆盖方法的优势。还有另一个实现可堆叠混合的技巧,我将把它描述为回答的更新
    • 我熟悉可堆叠演员模式,并在库中使用它。也许我很迂腐,但我不喜欢明显是从 Actor 扩展而来的 mixin 的特征。
    • 你能解释一下抽象覆盖吗?我以前从未遇到过。
    • abstract override 用于当 trait 说“我声明这个方法,我也给它一个实现,但是在扩展我的 trait 时你还必须提供你自己的实现。所以我可以覆盖它。 "这有点疯狂,但有道理。如果你看它调用并依赖于 super.preStart(),自信地调用它并加起来它的效果。它让我们想起了装饰器模式。
    【解决方案2】:

    您可以使用 self-type 来要求 trait 只能混入到 Actors 中。

    trait MyMixin { self: Actor =>
      println(self.path)
    }
    
    trait MyActor extends Actor with MyMixin
    

    MyMixin 不是相当演员,但它只能由演员类扩展。

    【讨论】:

    • 我为 mixin 提供了一个 self 类型的注解,以强制执行它必须与 AuctionActor(扩展 Actor)混合的约束。有什么理由使用“self”而不是“this”?
    • 你可以随便叫它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    • 2015-09-09
    • 2015-06-11
    相关资源
    最近更新 更多