Search code examples
scalaakkamixinsakka-actor

Accessing Akka Actor context inside a mixin


I would like to define a trait that can be mixed in with an Akka actor that schedules a receive timeout after some finite duration. Here is a sketch of what I want to do...

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]]

...but I don't understand when the context.setReceiveTimeout will be called. Will it be called as part of the constructor when the MyFancyAuctionActor is called? Or will it get called earlier and thus throw some kind of error due to fact that timeout hasn't been defined.


Solution

  • I suggest controlling trigger of your schedule using actor's lifecycle event hooks.if you have your trait extend an actor like this:

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

    you'll have access to many of the lifecycle event hooks of the actor such as preStart(), postStop() and many more.

    So you can easily do:

    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?
      }    
    }
    

    Update

    If you want to implement a stackable mixins structure. you'd do something similar to above.

    //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)
      }
    }
    

    you can have as many of traits that extend your class AuctionActor stacked together.