在scala中迭代时抛出异常

时间:2013-06-09 18:13:56

标签: scala file-io exception-handling iterator actor

我有一个基于actor的系统,我正在读取一个位于S3存储桶中的外部文件,并移动每个文件行并将其发送给处理该特定行的另一个actor。我理解的是在读取文件时抛出异常会发生什么。

我的代码如下:

import akka.actor._
import akka.actor.ActorSystem

class FileWorker(processorWorker: ActorRef) extends Actor with ActorLogging {

  val fileUtils = new S3Utils()

  private def processFile(fileLocation: String): Unit = {
    try{
         fileUtils.getLinesFromLocation(fileLocation).foreach {
         r =>
        {
           //Some processing happens for the line
            }
          }
        }
    }
    }catch{
      case e:Exception => log.error("Issue processing files from the following location %s".format(fileLocation))
    }
  }

  def receive() = {
    case fileLocation: String => {
      processFile(fileLocation)
    }
  }
}

在我的S3Utils课程中,我已将getLinesFromLocation方法定义如下:

 def getLinesFromLocation(fileLocation: String): Iterator[String] = {
    try{
       for {
             fileEntry <- getFileInfo(root,fileLocation)
          } yield fileEntry
    }catch{
      case e:Exception => logger.error("Issue with file location %s:         %s".format(fileLocation,e.getStackTraceString));throw e
    }
  }

我实际读取文件的方法是在私有方法getFileInfo

中定义的
 private def getFileInfo(rootBucket: String,fileLocation: String): Iterator[String] = {
    implicit val codec = Codec(Codec.UTF8)
    codec.onMalformedInput(CodingErrorAction.IGNORE)
    codec.onUnmappableCharacter(CodingErrorAction.IGNORE)
    Source.fromInputStream(s3Client.
                       getObject(rootBucket,fileLocation).
                       getObjectContent()).getLines
  }

我已经编写了上面的部分,假设坐在S3上的底层文件不会被缓存在任何地方,我将简单地遍历恒定空间中的各个行并处理它们。如果读取特定行存在问题,迭代器将继续运行而不会影响Actor。

我的第一个问题是,我对迭代器的理解是否正确?实际上,我实际上是从底层文件系统(在这种情况下是S3存储桶)中读取行,而不对内存施加任何压力/或引入任何内存泄漏。

接下来的问题是,如果迭代器在读取单个条目时遇到错误,则整个迭代过程都会被终止,或者它会移动到下一个条目。

我的最后一个问题是,我的文件处理逻辑是否正确编写?

很高兴能够对此有所了解。

由于

1 个答案:

答案 0 :(得分:1)

看起来亚马逊s3没有异步实现,我们被固定的演员所困扰。因此,您的实现是正确的,只要您为每个连接分配一个线程并且不会阻止输入,并且不会使用太多连接。

要采取的重要步骤:

1)processFile不应该阻止当前线程。最好将它的输入委托给另一个演员:

 private def processFile(fileLocation: String): Unit = {
     ...
         fileUtils.getLinesFromLocation(fileLocation).foreach {  r =>
            lineWorker ! FileLine(fileLocation, r)
         }

    ...
 }

2)让FileWorker成为一个固定的演员:

## in application.config:
my-pinned-dispatcher {
    executor = "thread-pool-executor"
    type = PinnedDispatcher
}

// in the code:  
val fileWorker = context.actorOf(Props(classOf[FileWorker], lineWorker).withDispatcher("my-pinned-dispatcher"), "FileWorker")
  

如果迭代器在读取单个条目时遇到错误,整个迭代过程是否会被终止?

是的,你的整个过程将被杀死,演员将从它的邮箱中接下一份工作。