2015-06-20 15 views
5

Version viết tắt:Java/Scala Future dẫn dắt bởi một callback

Làm thế nào tôi có thể tạo ra một Promise<Result> được hoàn thành trên một kích hoạt của một callback?

Version Long:

tôi đang làm việc trên một ứng dụng mà những giao dịch với các dịch vụ SOAP của bên thứ ba. Một yêu cầu từ người dùng đại biểu cho nhiều dịch vụ SOAP cùng một lúc, tổng hợp các kết quả và gửi lại cho người dùng.

Hệ thống cần phải mở rộng và cho phép nhiều người dùng đồng thời. Khi mỗi yêu cầu của người dùng kết thúc kích hoạt khoảng 10 cuộc gọi dịch vụ web và mỗi lần chặn cuộc gọi trong khoảng 1 giây, hệ thống cần phải được thiết kế với I/O không chặn.

Tôi đang sử dụng Apache CXF trong khung chơi (Java) cho hệ thống này. Tôi đã quản lý để tạo ra các proxy không đồng bộ WS Client và cho phép vận chuyển async. Những gì tôi không thể tìm ra là làm thế nào để trở về một chủ đề tương lai để chơi khi tôi đã ủy nhiệm cho nhiều proxy dịch vụ Web và kết quả sẽ được lấy như callbacks.

Tùy chọn 1: Sử dụng phương thức async gọi lại Java Tương lai.

Như được mô tả trong chủ đề scala.concurrent.Future wrapper for java.util.concurrent.Future này, không có cách nào để chúng tôi có thể chuyển đổi tương lai Java thành Scala Future. Cách duy nhất để có được kết quả từ tương lai là làm Future.get() để chặn người gọi. Vì các proxy được tạo ra của CXF trả về Java Future, tùy chọn này bị loại trừ.

Tùy chọn 2: Sử dụng Scala Future.

Vì CXF tạo giao diện proxy, tôi không chắc liệu có cách nào can thiệp và trả lại tương lai Scala (AFAIK Akka sử dụng Scala Futures) thay vì Java Future không?

Tùy chọn 3: Sử dụng phương pháp gọi lại.

Các phương thức không đồng bộ được tạo bởi CXF trả về Java Future cũng nhận đối tượng gọi lại mà tôi cho rằng sẽ cung cấp gọi lại khi kết quả đã sẵn sàng. Để sử dụng cách tiếp cận này, tôi sẽ cần phải trả về một tương lai mà sẽ đợi cho đến khi tôi nhận được một cuộc gọi lại.

Tôi nghĩ rằng Tùy chọn 3 là hứa hẹn nhất, mặc dù tôi không có ý tưởng về cách tôi có thể trả lại Lời hứa sẽ được hoàn thành khi nhận được cuộc gọi lại. Tôi có thể có thể có một sợi chờ đợi trong một while(true) và chờ đợi ở giữa cho đến khi kết quả có sẵn. Một lần nữa, tôi không biết làm thế nào tôi có thể đi vào wait mà không ngăn chặn các chủ đề?

Tóm lại, tôi đang cố gắng xây dựng một hệ thống đang thực hiện rất nhiều cuộc gọi dịch vụ web SOAP, trong đó mỗi cuộc gọi chặn cho thời gian đáng kể. Hệ thống có thể dễ dàng chạy ra khỏi chủ đề trong trường hợp có nhiều cuộc gọi dịch vụ web đồng thời. Tôi đang tìm kiếm giải pháp không dựa trên I/O mà có thể cho phép nhiều cuộc gọi dịch vụ web đang diễn ra cùng một lúc.

+0

Ngạc nhiên với 4 phiếu bầu để đóng câu hỏi ngay cả khi tôi có phiên bản ngắn hơn của câu hỏi rất chính xác. –

Trả lời

1

Tùy chọn 3 có vẻ tốt :) Một vài lần nhập để bắt đầu ...

và, chỉ để minh họa cho điểm, đây là một API CXF chế giễu mà mất callback:

def fetch(url: String, callback: String => Unit) = { 
    callback(s"results for $url") 
} 

Tạo một lời hứa, hãy gọi API với lời hứa như callback:

val promise = Promise[String] 
fetch("http://corp/api", result => promise.success(result)) 

Sau đó, bạn có thể chụp promise.future là một phiên bản của Future vào ứng dụng Play của bạn.

Để kiểm tra, bạn có thể làm điều này:

Await.result(promise.future, Duration.Inf) 

mà sẽ ngăn chặn chờ đợi kết quả, lúc này bạn sẽ thấy "kết quả cho http://corp/api" trong giao diện điều khiển.

+2

Cảm ơn mã mẫu, mặc dù tôi đang sử dụng Play Java. Tôi nghĩ rằng điểm mà tôi đã bỏ lỡ là 'Lời hứa' chính xác là điều để đạt được điều này. Trong trường hợp Play Java, nó là 'play.libs.F.RedeemablePromise'. Vì vậy, tôi có thể trả về một thể hiện của 'RedeemablePromise' và chuyển giao xử lý của' javax.xml.ws.AsyncHandler' có đối tượng lời hứa được nhúng bên trong nó, để đối tượng gọi lại có thể ủy thác thành lời hứa thông qua lời gọi 'success()'. Tôi nghĩ rằng tôi hiểu sự khác biệt giữa Tương lai và Lời hứa bây giờ, mà tôi sử dụng để nghĩ là rất giống nhau. –

+1

Tôi đã quản lý để có được async làm việc bằng cách sử dụng 'Promise'. Cảm ơn @bjfletcher –