Вопрос по scala, akka, rest, polling, play2-mini – Акка для REST опросов

12

Я пытаюсь связать большое приложение Scala + Akka + PlayMini с внешним REST API. Идея состоит в том, чтобы периодически опрашивать (в основном каждые 1-10 минут) корневой URL-адрес, а затем сканировать URL-адреса подуровня для извлечения данных, которые затем отправляются в очередь сообщений.

Я придумал два способа сделать это:

1st way

Создайте иерархию действующих лиц в соответствии со структурой пути ресурса API. В случае с Google Локатором это будет означать, например,

Actor 'latitude/v1/currentLocation' polls https://www.googleapis.com/latitude/v1/currentLocation Actor 'latitude/v1/location' polls https://www.googleapis.com/latitude/v1/location Actor 'latitude/v1/location/1' polls https://www.googleapis.com/latitude/v1/location/1 Actor 'latitude/v1/location/2' polls https://www.googleapis.com/latitude/v1/location/2 Actor 'latitude/v1/location/3' polls https://www.googleapis.com/latitude/v1/location/3 etc.

В этом случае каждый участник отвечает за периодический опрос своего связанного ресурса, а также за создание / удаление дочерних акторов для ресурсов пути следующего уровня (т. Е. Актер latitude / v1 / location 'создает акторов 1, 2, 3 и т. Д.). для всех мест, о которых он узнает путем опросаhttps://www.googleapis.com/latitude/v1/location).

2nd way

Создайте пул идентичных участников опроса, которые получают запросы на опрос (содержащие путь к ресурсу) с балансировкой нагрузки маршрутизатором, опрашивают URL-адрес один раз, выполняют некоторую обработку и планируют запросы на опрос (как для ресурсов следующего уровня, так и для опрошенного URL-адреса) , В Google Локаторе это будет означать, например:

1 роутер, п поллер актеров. Первоначальный запрос на опросhttps://www.googleapis.com/latitude/v1/location приводит к нескольким новым (немедленным) запросам на опросhttps://www.googleapis.com/latitude/v1/location/1, https://www.googleapis.com/latitude/v1/location/2и т. д. и один (отложенный) запрос опроса для одного и того же ресурса, т.е.https://www.googleapis.com/latitude/v1/location.

Я реализовал оба решения и не могу сразу заметить какое-либо существенное различие в производительности, по крайней мере, не для API и частот опроса, которые меня интересуют. Я считаю, что первый подход несколько проще рассуждать и, возможно, проще использовать с системой .scheduler.schedule (...), чем второй подход (где мне нужно планироватьOnce (...)). Кроме того, предполагая, что ресурсы вложены на нескольких уровнях и несколько недолговечны (например, несколько ресурсов могут быть добавлены / удалены между каждым опросом), управление жизненным циклом akka позволяет легко убить целую ветвь в 1-м случае. Второй подход должен (теоретически) быть быстрее, а код несколько проще для написания.

Мои вопросы:

What approach seems to be the best (in terms of performance, extensibility, code complexity, etc.)? Do you see anything wrong with the design of either approach (esp. the 1st one)? Has anyone tried to implement anything similar? How was it done?

Спасибо!

Я бы больше беспокоился о путях ошибок. Что происходит, если существует временный сбой определенного промежуточного пути; ты повторяешь? Будет ли сбой любого данного дочернего актера также причиной сбоя родительского актера? При достаточном масштабе вы почти гарантированно получитеsome преходящие сбои со стороны детей. Ross Judson

Ваш Ответ

1   ответ
1

который затем пинает асинхронные запросы ресурсов по расписанию?

Я не эксперт, использующий Akka, но я дал этому шанс:

Объект poller, который просматривает список ресурсов для извлечения:

import akka.util.duration._
import akka.actor._
import play.api.Play.current
import play.api.libs.concurrent.Akka

object Poller {
  val poller = Akka.system.actorOf(Props(new Actor {
    def receive = {
      case x: String => Akka.system.actorOf(Props[ActingSpider], name=x.filter(_.isLetterOrDigit)) ! x
    }
  }))

  def start(l: List[String]): List[Cancellable] =
    l.map(Akka.system.scheduler.schedule(3 seconds, 3 seconds, poller, _))

  def stop(c: Cancellable) {c.cancel()}
}

Актер, который читает ресурс асинхронно и запускает больше операций асинхронного чтения. Вы можете поставить отправку сообщения по расписанию, а не немедленно позвонить, если это будет добрее:

import akka.actor.{Props, Actor}
import java.io.File

class ActingSpider extends Actor {
  import context._
  def receive = {
    case name: String => {
      println("reading " + name)
      new File(name) match {
        case f if f.exists() => spider(f)
        case _ => println("File not found")
      }
      context.stop(self)
    }
  }

  def spider(file: File) {
    io.Source.fromFile(file).getLines().foreach(l => {
      val k = actorOf(Props[ActingSpider], name=l.filter(_.isLetterOrDigit))
      k ! l
    })
  }
}

Похожие вопросы