score:1

Accepted answer

when you schedule a message with

system.scheduler.scheduleonce(...)

a sender of that message is deadletters which is what you are trying to send message to in

sender ! returninfluencemessage(source)

and it is also what error message says.

score:2

@martynas is correct in that your sender ref will be the deadletter ref when your code is setup the way it is. the main issue is that you send in a message from outside of the actor system (via the scheduler) and then when you use forward, you continue to propagate the fact that you don't have a sender down into the next actor. you can remedy this by using a tell (!) instead of forward. i have modified your code sample to show this (as well as some other changes described after the code sample):

import akka.actor._
import concurrent.duration._

sealed trait message
case class returninfluencemessage(source: actorref) extends message
case class setinfluences(source: actorref) extends message
case object getinfluence extends message

class listener extends actor {
  def receive = {
    case returninfluencemessage(s0urce) => println(s"listener: received influence ($s0urce)")
  }
}

class entity extends actor {
  val influences = context.actorof(props[influences], name = "influences")
  def receive = {
    case si @ setinfluences(s0urce) => 
      influences ! si

    case getinfluence => 
      influences ! getinfluence

    case rim @ returninfluencemessage(source) =>
      source ! rim
  }
}

class influences extends actor {
  def receive = setinfluence

  def setinfluence:receive = {
    case setinfluences(s0urce)  => 
      println (s"influences: received $s0urce")
      println (s"influences: influence set to $s0urce")    
      context.become(withsource(s0urce) orelse setinfluence)
  }

  def withsource(source:actorref):receive = {
    case getinfluence =>
      println (s"influences: influence sent to $source")
      sender ! returninfluencemessage(source)      
  }    
}

object main extends app {
  val system = akka.actor.actorsystem("mysystem")
  val abel = system.actorof(props[listener], name = "listener")
  val cain = system.actorof(props[entity], name = "entity")

  import system.dispatcher
  system.scheduler.scheduleonce(1500 milliseconds, cain, setinfluences(abel))
  system.scheduler.scheduleonce(3000 milliseconds, cain, getinfluence)
}

when i ran this i did not get any deadletters. other changes include:

  • formatting (2 spaces for indents, correct casing for var/vals)
  • changed getinfluence into a case object as it did not have any fields
  • used variable binding in the case statements to capture a ref to the message (via the @ symbol) when we needed to send that message along
  • used a two state setup for the influences actor where it is first waiting for the state to be set (the source ref) and then switches to a state where it is able to respond properly to a getinfluences message. probably want to explicitly handle a getinfluences message when in the initial state as for now it's just an unhandled message.
  • got rid of the use of children.foreach as you already had a ref to the only child of that actor, so it seemed unnecessary to use this construct. i would use that construct if you had a variable amount of children to send to and in this example you don't.

Related Query

More Query from same tag