簡體   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