我需要对地址对象进行地理编码,然后将更新的地址存储在搜索引擎中。这可以简化为获取一个对象,对该对象执行一个长时间运行的操作,然后持久化该对象。这意味着有一个操作顺序要求第一个操作在持久性发生之前完成。
我想使用 Akka 将其移出执行的主线程。
我最初的想法是使用一对 Futures 来完成此操作,但Futures 文档并不完全清楚哪种行为(折叠、映射等)保证一个 Future 在另一个之前执行。
我首先创建了两个函数,defferedGeocode
它们deferredWriteToSearchEngine
为各自的操作返回 Futures。我使用 将它们链接在一起Future<>.andThen(new OnComplete...)
,但这很快就会变得笨拙:
Future<Address> geocodeFuture = defferedGeocode(ec, address);
geocodeFuture.andThen(new OnComplete<Address>() {
public void onComplete(Throwable failure, Address geocodedAddress) {
if (geocodedAddress != null) {
Future<Address> searchEngineFuture = deferredWriteToSearchEngine(ec, addressSearchService, geocodedAddress);
searchEngineFuture.andThen(new OnComplete<Address>() {
public void onComplete(Throwable failure, Address savedAddress) {
// process search engine results
}
});
}
}
}, ec);
然后deferredGeocode
是这样实现的:
private Future<Address> defferedGeocode(
final ExecutionContext ec,
final Address address) {
return Futures.future(new Callable<Address>() {
public Address call() throws Exception {
log.debug("Geocoding Address...");
return address;
}
}, ec);
};
deferredWriteToSearchEngine
与 非常相似deferredGeocode
,只是它将搜索引擎服务作为附加的最终参数。
我的理解是期货应该用于执行计算并且不应该有副作用。在这种情况下,对地址进行地理编码是计算,所以我认为使用 Future 是合理的,但写入搜索引擎肯定是一个副作用。
Akka 的最佳实践是什么?如何避免所有嵌套调用,但确保地理编码和搜索引擎写入都在主线程之外完成?
有没有更合适的工具?
更新:
根据 Viktor 下面的评论,我现在正在尝试这段代码:
ExecutionContext ec;
private Future<Address> addressBackgroundProcess(Address address) {
Future<Address> geocodeFuture = addressGeocodeFutureFactory.defferedGeocode(address);
return geocodeFuture.flatMap(new Mapper<Address, Future<Address>>() {
@Override
public Future<Address> apply(Address geoAddress) {
return addressSearchEngineFutureFactory.deferredWriteToSearchEngine(geoAddress);
}
}, ec);
}
这似乎工作正常,除了一个我不满意的问题。我们在 Spring IOC 代码库中工作,因此我想将 ExecutionContext 注入 FutureFactory 对象,但这个函数(在我们的 DAO 中)需要了解 ExecutionContext 似乎是错误的。
对我来说 flatMap() 函数根本需要一个 EC 似乎很奇怪,因为两个期货都提供了一个。
有没有办法保持关注点分离?我是在糟糕地构建代码,还是这正是它需要的方式?
我考虑在 FutureFactory 中创建一个允许链接 FutureFactory 的接口,因此 flatMap() 调用将被封装在 FutureFactory 基类中,但这似乎是故意破坏 Akka 的设计决策。