在Kotlin中,如何将Kovenant承诺与Elasticsearch异步响应集成?

时间:2016-09-18 23:26:49

标签: elasticsearch kotlin kovenant

我在我的Kotlin应用程序中使用Kovenant,而我正在调用具有自己的异步API的Elasticsearch。我宁愿使用承诺,但我能想出的最好的东西是:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 1
file size               (blocks, -f) unlimited
pending signals                 (-i) 16382
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 512
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) 1800
max user processes              (-u) 42
virtual memory          (kbytes, -v) 786432
file locks                      (-x) unlimited

哪个是Kovenant异步任务线程,然后Elasticsearch使用其池中的线程,然后task { esClient.prepareSearch("index123") .setQuery(QueryBuilders.matchAllQuery()) .execute().actionGet() } then { ... } success { ... } fail { ... } 同步阻止Elasticsearch返回结果。在阻止其他线程的同时产生新线程似乎很愚蠢。有没有一种方法可以更紧密地集成线程调度?

注意: 此问题是由作者(Self-Answered Questions)故意编写和回答的,因此可以在SO中分享有趣问题的解决方案。

1 个答案:

答案 0 :(得分:3)

您可以使用Kovenant Deferred class创建承诺,而无需像您在示例中那样通过异步actionGet()进行调度。该模型基本上是:

  1. 创建延迟实例
  2. 连接到异步处理程序并根据异步回调解析或拒绝延迟
  3. task返回给来电者
  4. 在代码中,这看起来像:

    deferred.promise

    这样做的一种可重用的方法是首先创建一个适配器,它可以让Elasticsearch希望fun doSearch(): Promise<SearchResponse, Throwable> { val deferred = deferred<Response, Throwable>() esClient.prepareSearch("index") .setQuery(QueryBuilders.matchAllQuery()) .execute(object: ActionListener<T> { override fun onResponse(response: T) { deferred.resolve(response) } override fun onFailure(e: Throwable) { deferred.reject(e) }) return deferred.promise } 能够一致地使用承诺:

    ActionListener

    注意:fun <T: Any> promiseResult(deferred: Deferred<T, Exception>): ActionListener<T> { return object: ActionListener<T> { override fun onResponse(response: T) { deferred.resolve(response) } override fun onFailure(e: Throwable) { deferred.reject(wrapThrowable(e)) } } } class WrappedThrowableException(cause: Throwable): Exception(cause.message, cause) fun wrapThrowable(rawEx: Throwable): Exception = if (rawEx is Exception) rawEx else WrappedThrowableException(rawEx) 方法可以将wrapThrowable()更改为Throwable,因为Kovenant的当前版本(Exception)有一些方法可以预期拒绝类型承诺来自3.3.0,例如bind() ),如果您使用unwrap()代替嵌套承诺,则可以使用Exception

    现在使用此适配器功能一般扩展Elasticsearch Throwable,这几乎是你唯一可以调用ActionRequestBuilder的东西;创建新的execute()扩展功能:

    promise()

    现在,您可以拨打fun <Request: ActionRequest<*>, Response: ActionResponse, RequestBuilder: ActionRequestBuilder<*, *, *, *>, Client: ElasticsearchClient<*>> ActionRequestBuilder<Request, Response, RequestBuilder, Client>.promise(): Promise<Response, Exception> { val deferred = deferred<Response, Exception>() this.execute(promiseResult(deferred)) return deferred.promise } 而不是promise()

    execute()

    开始束缚你的承诺......

    esClient.prepareSearch("index")
                .setQuery(QueryBuilders.matchAllQuery())
                .promise()
    

    如果您想要链接的嵌套承诺没有嵌套更深,那么您应该熟悉bind()unwrap()。如果您不想包含kovenant-functional,则可以在上述情况下使用esClient.admin().indices().prepareCreate("index1").setSettings("...").promise() .bind { esClient.admin().cluster().prepareHealth() .setWaitForGreenStatus() .promise() } bind { esClient.prepareIndex("index1", "type1") .setSource(...) .promise() } bind { esClient.prepareSearch("index1") .setQuery(QueryBuilders.matchAllQuery()) .promise() } then { searchResults -> // ... use searchResults }.success { // ... }.fail { // ... } } 代替unwrap().then

    由于Elasticsearch客户端中所有请求对象的一致性,您在Elasticsearch中的每次调用都可以使用bind而不是promise()