我有一种在Amazon S3上创建zip文件的方法,该文件使用Rinofly的play-s3抽象(不是真的很重要 - 主要是使用Future
)。该方法如下所示:
def createZip(key: String): Future[String] = {
val bucket = //get S3 bucket
val zipFileName = //name of zip file
val futureFile = bucket get key //Returns Future[BucketFile]
futureFile
.map(bucketFile => newZipFile(bucketFile.name, bucketFile.content) //Create zip file from original key
.map(newZipFile => bucket + newZipFile) //Does an S3 PUT of the zip file in the bucket and returns Unit
.map(unit => zipFileName) //Maps the returned unit to the zip file name once the zip file has been created and properly uploaded to S3
}
如您所见,该方法采用S3键并返回已创建的相应zip文件的名称。
我通过REPL发现第二个map方法执行新zip文件的S3 put会抛出异常,因为S3凭据没有权限。没问题 - 我知道如何解决这个问题。
问题是我不知道是这种情况,直到我在REPL中逐行运行所有内容。换句话说,该方法给出了成功的误报。
当我在REPL中运行整个方法时,我得到了这个:
scala> val a = createZip("test.zip")
a: scala.concurrent.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@3174c2d7
scala> import scala.concurrent.Await
Await.result(a, 120.seconds)
scala> res1: String = "test.zip"
结果应该是Throwable
(S3Exception
FWIW)的一个实例。
此外,当我在REPL中应用onSuccess
和onFailure
个回调时,会触发onSuccess
。
显然,我正在做一些事情,以便在存储桶添加调用中吞下或隐藏异常的生成。
我很想知道如何确保所有错误都暴露出来。
答案 0 :(得分:1)
bucket.add
返回Future[Unit]
而不是Unit
。所以在这一行:
.map(unit => zipFileName)
您实际上正在将Future[Unit]
映射到String
,这就是错误丢失的原因,因为您正在丢弃该响应。这map
:
.map(newZipFile => bucket + newZipFile)
应该成为flatMap
从Future[Future[Unit]]
到Future[Unit]
正确展平。
编译器不够聪明,无法推断您不想映射Future[Unit] => B
,但是如果您要添加类型注释,则无法编译。
.map{unit: Unit => zipFileName} // Would complain the type is not Future[Unit]