我在我的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中分享有趣问题的解决方案。
答案 0 :(得分:3)
您可以使用Kovenant Deferred
class创建承诺,而无需像您在示例中那样通过异步actionGet()
进行调度。该模型基本上是:
task
返回给来电者在代码中,这看起来像:
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()
。