Arhn - архитектура программирования

Ошибка с DeadLetters и ActorRef

Я столкнулся с ошибкой при запуске моего проекта, которую не могу решить.

Вот мой код:

import akka.actor._
import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.ScalaActorRef
import akka.pattern.gracefulStop
import akka.util._
import java.util.Calendar
import java.util.concurrent._
import java.text.SimpleDateFormat
import scala.Array._
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

sealed trait Message
case class ReturnInfluenceMessage(source: ActorRef) extends Message
case class SetInfluences(source: ActorRef) extends Message
case class GetInfluence() extends Message

class Listener extends Actor {
    def receive = {
        case ReturnInfluenceMessage(s0urce) => println ("Listener: received influence (" +     s0urce + ")")
    }
}

class Entity extends Actor {
    val Influences = context.actorOf(Props[Influences], name = "Influences")
    def receive = {
        case SetInfluences(s0urce) => context.children foreach     (_.forward(SetInfluences(s0urce)))
        case GetInfluence => context.children foreach (_.forward(GetInfluence))
        case ReturnInfluenceMessage(source) =>
            source ! ReturnInfluenceMessage(source)
    }
}

class Influences extends Actor {
    private var source: ActorRef = _
    def receive = {
        case SetInfluences(s0urce)  => 
            source = s0urce
            println ("Influences: received " + s0urce)
            println ("Influences: Influence set to " + source)
        case GetInfluence =>
            println ("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")

    system.scheduler.scheduleOnce(1500 milliseconds, Cain, SetInfluences(Abel))
    system.scheduler.scheduleOnce(3000 milliseconds, Cain, GetInfluence)
}

Здесь ошибка:

 [INFO] [08/29/2014 15:39:08.330] [mySystem-akka.actor.default-dispatcher-2] [akka://mySystem
 /deadLetters] Message [ReturnInfluenceMessage] from Actor[akka://mySystem/user/Entity
 /Shadow/Influences#1407138271] to Actor[akka://mySystem/deadLetters] was not 
 delivered. [1] dead letters encountered. This logging can be turned off or adjusted 
 with configuration settings
 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

Я пытаюсь установить переменную source актера Cain, чтобы этот последний отправлял ActorRef из Abel, которому сообщение, отображающее переменную source, и отображал его. Ошибка возникает здесь:

source ! ReturnInfluenceMessage(source)

, и я не знаю, почему это происходит.

02.09.2014

Ответы:


1

Когда вы планируете сообщение с

system.scheduler.scheduleOnce(...)

отправителем этого сообщения является DeadLetters, которому вы пытаетесь отправить сообщение в

sender ! ReturnInfluenceMessage(source)

и это также то, что говорит сообщение об ошибке.

02.09.2014
  • Хорошо, спасибо за ответ. Я нашел способ обойти проблему, заменив sender на context.parent, простой. Но это не решает проблему. Могу ли я связаться с не-DeadLetters отправителем с помощью sender? 02.09.2014
  • Позвольте мне перефразировать мой ответ. sender равно DeadLetters при обработке сообщения, отправленного с использованием system.scheduler.scheduleOnce(...), что и делает ваш код. 02.09.2014

  • 2

    @Martynas прав в том, что ваш sender ref будет DeadLetter ref, когда ваш код настроен так, как он есть. Основная проблема заключается в том, что вы отправляете сообщение из-за пределов системы акторов (через планировщик), а затем, когда вы используете forward, вы продолжаете распространять тот факт, что у вас нет отправителя, в следующем акторе. Вы можете исправить это, используя tell (!) вместо переадресации. Я изменил ваш пример кода, чтобы показать это (а также некоторые другие изменения, описанные после примера кода):

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

    Когда я запустил это, я не получил никаких мертвых писем. Другие изменения включают в себя:

    • Форматирование (2 пробела для отступов, правильный регистр для var/vals)
    • Изменил GetInfluence на объект дела, так как у него не было полей
    • Использовалась привязка переменных в операторах case для захвата ссылки на сообщение (через символ @), когда нам нужно было отправить это сообщение вместе.
    • Использована установка с двумя состояниями для актора Influences, где он сначала ожидает установки состояния (ссылка source), а затем переключается в состояние, в котором он может правильно реагировать на сообщение GetInfluences. Возможно, вы захотите явно обработать сообщение GetInfluences в начальном состоянии, так как сейчас это просто необработанное сообщение.
    • Избавились от использования children.foreach, поскольку у вас уже была ссылка на единственного потомка этого актора, поэтому использование этой конструкции казалось ненужным. Я бы использовал эту конструкцию, если бы у вас было переменное количество дочерних элементов для отправки, а в этом примере у вас его нет.
    02.09.2014
  • Спасибо. Но я не понимаю такой строки: case si @ SetInfluences(s0urce) =› влияет ! си 02.09.2014
  • @wipman, используя символ @ в операторе case, вы можете связать вещь после символа @ с переменной, используя вещь, которая стоит перед символом, в качестве имени переменной. Таким образом, мне не нужно воссоздавать класс case (как вы делали), если я хочу просто распространить его на другого актера (как я делаю через !). Это помогает сэкономить на ненужных затратах на создание экземпляра объекта. Ознакомьтесь с разделом привязки переменных по этой ссылке для получения более подробной информации: artima .com/pins1ed/case-classes-and-pattern-matching.html 02.09.2014
  • .@ cmbaxter Большое спасибо за советы и все! Это мне очень помогает! 02.09.2014
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..