如何使用 Futures 设计和调用 Scala API

How to Design and Call Scala API with Futures

开始学习 scala 和 designing/implementing 异步执行。我的问题是关于如何设计 APIs(然后调用)它们以进行 return 单元但可能不会立即进行的操作。例如,在下面的代码片段中,函数(使用 Slick 3.0)将用户插入到数据库中。 Unit 是此函数的正确 return 类型吗?如果是,调用方如何知道 if/when 新插入的用户成功?

override def insertOrUpdate(entity: User): Unit = {
     database.run(users.insertOrUpdate(entity))
}

例如,如果以上异步执行并且调用者类似于

//create and insert new user with id = 7
val newUser = User(7, "someName")
userRepo.insertOrUpdate(newUser)

呼叫者如何知道这样做是否安全

userRepo.findById(7)

在单元测试中,我知道如果我立即通过 findById 调用跟进插入调用,findById 将 return 什么都没有,但是如果我在插入和查找调用之间引入一些延迟,它会发现新用户。总而言之,为异步执行但没有自然 return 值来包装 Future 的函数设计 API 的正确方法是什么?

通常在使用 Futures 时,您会希望通过在 returned Future 上调用的方法进行任何进一步处理。例如:

val newUser = User(7, "someName")
val future = userRepo.insertOrUpdate(newUser)
future.onSuccess { outcome => // Here, 'outcome' will hold whatever was contained in the Future - Unit in your description above.
   val storedUser = userRepo.findById(7) // This will only execute once the future completes (successfully).
   ...
}

还有许多其他有用的方法可用于操作 Future(或它们的集合),例如 "onFailure"、"recover"、"map" 和 "flatMap".

尽量不要在 Future 上等到越晚越好 - 最好让 Play 或 Spray 或您可能碰巧使用的任何其他框架为您处理(参见 here例如,有关执行此操作的 Play 文档)。

最后,就您要插入的数据库调用而言,我会考虑让调用 return 至少是一个布尔值,或者更好的是插入新条目的主键,而不是 Unit.