Scala和Akka:背景工作

Scala和Akka:背景工作,scala,playframework,akka,Scala,Playframework,Akka,我目前正在开发一个Play应用程序,它有一个后台工作,应该定期发送我想使用Akka的邮件。我必须补充一点,我对Scala/Play/Akka非常陌生 目前,我有以下设置: // JobModule.scala bind(classOf[MailJobScheduler]).asEagerSingleton() 这应该会启动下面的代码,它每秒钟都会工作 // MailJobScheduler.scala val mailActor = actorSystem.actorOf(MailActor.

我目前正在开发一个Play应用程序,它有一个后台工作,应该定期发送我想使用Akka的邮件。我必须补充一点,我对Scala/Play/Akka非常陌生

目前,我有以下设置:

// JobModule.scala
bind(classOf[MailJobScheduler]).asEagerSingleton()
这应该会启动下面的代码,它每秒钟都会工作

// MailJobScheduler.scala
val mailActor = actorSystem.actorOf(MailActor.props, "mail-actor")

actorSystem.scheduler.schedule(0 seconds, 1 seconds) {
    // check how many mails have to be sent and sent messages to the mailActor 
}
可能是每秒应该发送多封新的邮件。我想知道:如果我每秒向邮件参与者发送10条消息,那么真的只有一个参与者需要做所有的工作,还是会有多个参与者同时做这些工作


如果是一个参与者,我怎么可以有多个参与者来分配工作,我可以/应该有多少参与者?

使用Akka streams怎么样

import akka.Done
import akka.stream.{KillSwitch, KillSwitches, OverflowStrategy}
import akka.stream.scaladsl.{Keep, Sink, Source}
import scala.concurrent.duration._
import scala.concurrent.Future

object BatchEmailSender {
  sealed trait Msg
  case object Tick extends Msg
  case class Email(toAddress: String, body: String) extends Msg

  def apply(sendEmail: Email => Future[Done], sendInterval: FiniteDuration = 10.seconds)(implicit mat: ActorMaterializer)
    : (Email => Unit, KillSwitch) = {
    val emailQueue = scala.collection.mutable.Queue[Email]()

    val (emailCmdQueue, killSwitch) = Source.queue[Msg](0, OverflowStrategy.backpressure)
      .merge(Source.tick(0.seconds, sendInterval, Tick))
      .viaMat(KillSwitches.single)(Keep.both)
      .toMat(Sink.foreach {
        case newEmail: Email =>
          emailQueue.enqueue(newEmail)
        case Tick =>
          emailQueue.dequeueAll(_ => true).foreach { email =>
            sendEmail(email).onFailure { case e =>
              println(s"Error sending email to ${email.toAddress}: $e")
            }
          }
      })(Keep.left)
      .run()

    (emailCmdQueue.offer(_), killSwitch)
  }
}
您需要一个sendEmail功能,然后它会像这样工作:

import scala.concurrent.ExecutionContext.Implicits.global // TODO: remove me

object TestApp extends App {
  import BatchEmailSender._
  implicit val system = ActorSystem()
  implicit val materializer = ActorMaterializer()

  def sendEmail(email: Email): Future[Done] ={
    println(s"Sending email $email") // TODO: insert real email sender code here
    Future.successful(Done)
  }

  val (sendEmailEvery10s, killSwitch) = BatchEmailSender(sendEmail)
  sendEmailEvery10s(Email("foo@bar.com", "Email will arrive in 10s"))
  sendEmailEvery10s(Email("foo@bar.com", "Email will arrive in same batch"))
  Thread.sleep(11000)
  sendEmailEvery10s(Email("foo@bar.com", "Email will arrive after another 10s"))
  Thread.sleep(11000)
  killSwitch.shutdown()
}
我可能只是让你的生活复杂化了,但是Akka streams让你可以做这些事情,而不用担心哪个演员做什么,有背压,而且通常是更健壮的代码


如果Akka streams不存在,我会使用1名演员。累积actor中的所有消息,然后定期向其自身发送勾号

在示例中使用调度程序,但我看不出
mailActor
在这方面有什么帮助

actorSystem.scheduler.schedule(0 seconds, 1 seconds) {
    // just call the code the the checks for email
}
不要假设只有一个线程。i、 e