繁体   English   中英

在Akka中安排一对外部服务呼叫的最佳方法

[英]Best way to sequence a pair of external service calls in Akka

我需要对一个Address对象进行地理编码,然后将更新后的Address存储在搜索引擎中。 这可以简化为获取一个对象,对该对象执行一项长时间运行的操作,然后保留该对象。 这意味着有一个操作顺序要求在持久性发生之前完成第一个操作。

我想使用Akka将其移出执行主线程。

我最初的想法是使用一对Future来完成此操作,但是Future文档并不完全清楚哪种行为(折叠,映射等)可以保证一个Future在另一个行为之前执行。

我首先创建了两个函数defferedGeocodedeferredWriteToSearchEngine ,它们分别为相应的操作返回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,因为两个期货都提供了EC。

有没有办法保持关注点分离? 我是否对代码进行了错误的构造,或者这仅仅是它所需要的方式吗?

我考虑过在FutureFactory的接口中创建一个允许链接FutureFactory的接口,因此flatMap()调用将封装在FutureFactory的基类中,但这似乎有意破坏了故意的Akka设计决策。

警告:伪代码前面。

Future<Address> myFutureResult = deferredGeocode(ec, address).flatMap(
  new Mapper<Address, Future<Address>>() {
    public Future<Address> apply(Address geocodedAddress) {
      return deferredWriteToSearchEngine(ec, addressSearchService, geocodedAddress);
   }
  }, ec).map(
     new Mapper<Address, SomeResult>() {
       public SomeResult apply(Address savedAddress) {
         // Create SomeResult after deferredWriteToSearchEngine is done
       }
    }, ec);

看看它是不是嵌套的。 flatMap和map用于对操作进行排序。 当您希望仅将副作用操作运行到传递结果之前完全完成时,“ andThen”很有用。 当然,如果您在SAME future-instance上映射两次,则无法保证订购,但是由于我们是flatMapping并映射了返回的期货(根据文档为新期货),因此程序中存在清晰的数据流。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM