2013-11-04 11 views
2

我需要對地址對象進行地理編碼,然後將更新後的地址存儲在搜索引擎中。這可以簡化爲接受一個對象,對該對象執行一個長時間運行的操作,然後保持該對象。這意味着操作順序要求第一次操作在持續發生之前完成。在Akka排序一對外部服務調用的最佳方法

我想使用Akka將其移出主執行線程。

我最初的想法是使用一對期貨來實現這一點,但Futures documentation並不完全清楚哪些行爲(摺疊,地圖等)保證一個未來在另一個之前被執行。

我開始時創建了兩個函數,分別爲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的最佳做法是什麼?我怎樣才能避免所有的嵌套調用,但要確保地理編碼和搜索引擎都是在主線程之外完成的?

是否有更合適的工具?

更新:

基於以下維克托的意見,我想了下面這段代碼:

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設計決策的故意。

回答

1

警告:提前編碼。

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」對於當您希望僅影響副作用的操作在傳遞結果之前運行至完全完成狀態時非常有用。當然,如果您在同一個未來實例上映射兩次,那麼沒有訂單保證,但由於我們正在根據返回期貨(根據文檔的新增期貨)進行平鋪和映射,因此存在明確的數據流我們的計劃。

+0

這是deferredWriteToSearchEngine執行副作用的問題嗎?而且我對map()調用有點困惑......就是我們在寫入之後需要做另一個操作嗎? – JBCP

+0

不,這不是deferredWriteToSearchEngine執行副作用的問題。是的,最後一張地圖是在副作用之後做某事的一個例子。 –

+0

Hi @Viktor,請參閱我的更新評論。我對如何保護國際奧委會的主體並繼續使用期貨有點困惑。也許這應該是一個單獨的問題,但似乎相關。 – JBCP

相關問題