使用Akka Actors将附件发送到电子邮件网关

时间:2015-04-08 05:51:44

标签: scala akka

我是Akka的新手,Scala。

我必须构建一个服务,该服务会发送附带给emailIds附件的电子邮件。我使用Sendgrid作为网关。

对于附件,我在S3中上传了一个大小为28KB的文件。

我有REST服务,我可以通过它传递文档ID,我可以通过该服务将文档作为InputStream获取。现在,此输入流必须发送到许多电子邮件ID。下载文件的所有内容都由一个名为“attachmentActor”的actor处理,我在下面创建。

现在假设我有两个我需要发送附件的emailIds,我面临的问题是它没有向两者发送完整文件,事实上28KB文件分为16KB和12KB,最后发送到emailIds。 / p>

  • 所以emailId 1会收到16KB //实际应该有28KB

  • 电子邮件2将收到12KB //它应该实际上有28KB

以下是代码:

class SendgridConsumer{
  def receive(request: EmailRequest) = {
    val service = Sendgrid(username , password)
    val logData = request.logData
    var errorMessage = new String
    val attachmentRef = system.actorOf(Props[AttachmentRequestConsumer], "attachmentActor")
    val future = attachmentRef ? AttachmentRequest(request.documentId.get)
    var targetStream = Await.result(future, timeout.duration).asInstanceOf[InputStream]
    val results = request.emailContacts.par.map( emailContact => {
      val email=postData(new Email(),request , emailContact, targetStream,request.documentName.get)
      val sendGridResponse=service.send(email)

    }
}

// postData() creates an Email Object

// This is my Attachment Actor

class AttachmentRequestConsumer extends Actor with ActorLogging {

  def receive = {

    case request:AttachmentRequest => {

      log.info(" inside Attachment RequestConsumer with document Id:" + request.documentId)
      val req: HttpRequest = Http(url)
      val response = req.asBytes
      val targetStream = ByteSource.wrap(response.body).openStream()
      log.info("response body :" + response.body)
      sender ! targetStream
      targetStream.close()
    }
  }
}

1 个答案:

答案 0 :(得分:3)

你应该了解的关于actor的一件事是你不应该将可变对象(例如InputStream)作为消息发送(从技术上讲,只要你不改变它们就可以)。另一件事是发送消息是异步的。这意味着在另一个actor收到消息之前调用targetStream.close()。这可能是您获得截断附件的原因。

您可以做的一件事是发送数据而不是InputStream。像

这样的东西
def receive = {
    case request:AttachmentRequest => {
      log.info(" inside Attachment RequestConsumer with document Id:" + request.documentId)
      val req: HttpRequest = Http(url)
      val response = req.asBytes
      val data = ByteSource.wrap(response.body).read.toVector
      log.info("response body :" + response.body)
      sender ! data
    }
}

即如果您可以将附件的内容舒适地放入内存中。如果不是这种情况,您可以尝试break it into chunks or something.

在旁注中,您不应该在接收时阻止(Await.result)。更好的方法是向AttachmentRequestConsumer发送一条消息,然后在Seq[Byte]的接收中返回AttachmentResponse类型的消息(或者甚至更好的某些包装器,如SendgridConsumer)。