Handling Mappings when migrating Get Index call from Transport client to Rest High Level Client - elasticsearch

We are migrating from Transport Client to High Level Rest Client. How do we reconcile the difference in the mappings field of GetIndexResponse object returned from Transport client vs Rest High Level Client?
For transport client, we use this code to obtain the index information:
GetIndexResponse response = client.get()
.admin()
.indices()
.prepareGetIndex()
.setFeatures(GetIndexRequest.Feature.MAPPINGS, GetIndexRequest.Feature.SETTINGS)
.setIndices(indices)
.get();
The response mappings field is a ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>>
But for rest high level client, the mappings field is just a Map<String, MappingMetadata>.
Here is the code for High Level Rest Client:
GetIndexRequest request = new GetIndexRequest(indices);
request.addFeatures(GetIndexRequest.Feature.MAPPINGS, GetIndexRequest.Feature.SETTINGS);
try {
GetIndexResponse response = esClient.indices().get(request, RequestOptions.DEFAULT);
return
} catch (IOException ex) {
throw new SafeRuntimeException(ex);
}
}
These are the response object classes:
Transport Client: org.elasticsearch.action.admin.indices.get.GetIndexResponse
Rest High Level Client: org.elasticsearch.client.indices.GetIndexResponse

for mappings use the GetMappings request:
ImmutableOpenMap<String, ?> mappings = esclient.admin().indices().getMappings(new GetMappingsRequest()).actionGet().getMappings();
and you can also specify the indices you want.
EDIT: ah i see, you mean this:
client.indices().getMapping(new GetMappingsRequest().indices("index_name1", "index_name2"), RequestOptions.DEFAULT);
client.indices().getSettings(new GetSettingsRequest().indices("index_name1", "index_name2"), RequestOptions.DEFAULT);
when "client" is an instance of the High level REST client.

Related

how to retrieve the same error response received by webclient in spring reactive

I reveive a request from client, and to process that I have to make request to azure resource management app.
Now, if the client passes me incorrect info, and if I make direct call from postman to azure API, it returns me very useful info. refer below (below call contains incorrect query params) :
i get response like below in case of incorrect param passed :
{
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.MachineLearningServices/workspaces/workspace_XYZ/onlineEndpoints/Endpoint_XYZ' under resource group 'resourceGroupXYZ' was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix"
}
}
Now, I make this query using springboot reactive webclient API.
But I am not sure how to pass the same error back as it contains very useful info. The exception handling methods calls like onErrorReturn etc did not help me here to get the original error msg. :
response = getWebClient()
.post()
.uri(apiUrl)
.headers(h -> authToken)
.retrieve()
.bodyToMono(String.class)
// .onErrorReturn(response)
.block();

UnknownHostException when trying to connect using websocket

I have a use case where I need to send 2 requests to the server. The output of first request is used in second request so the calls have to be synchronous. I am using ktor (OkHttp)client websocket for this. I am failing at first attempt to even connect to the server with this error
Exception in thread "main" java.net.UnknownHostException: https: nodename nor servname provided, or not known
I suspect I haven't split my url properly and thats why its not able to connect to host.
Couple of qns
Is there any benefit to using websocket instead of using 2 separate Http requests?
Is there a way I can just pass URL to the websocket request?
Best and easiest way to get response and send another request?
I have been able to find very limited documentation on ktor client websocket.
const val HOST = "https://sample.com"
const val PATH1 = "/path/to/config?val1=<val1>&val2=<val2>"
const val PATH2 = "/path/to/config?val=<response_from_first_req>"
fun useSocket() {
val client = HttpClient() {
install(WebSockets)
}
runBlocking {
client.webSocket(method = HttpMethod.Get, host = HOST, path = PATH1) {
val othersMessage = incoming.receive() as? Frame.Text
println(othersMessage?.readText())
println("Testing")
}
}
client.close()
}
Thanks in advance.

How to set netty log level on selected spring boot Webclient instances

We have 2 different instances of spring boot Webclients. We want one of them to log all requests/responses and the other to log nothing. Settiing:
logging.level.reactor.netty.http.client=debug
in the application.properties file causes both instances to log requests/responses. Is there a way to programmatically set the log level on one of the instances to log debug levels and the other to not?
We create the first webclient like this:
WebClient.create();
For this one we don't want debug logging.
The second one, for which we want logging, we create like this:
return WebClient.builder()
.clientConnector(createWebClientWithTimeout())
// Add base url to all requests (callers only need to add the path and query params)
.baseUrl(baseUrl)
// Increase the buffer size from 256K to 1M
.codecs(configurer -> configurer
.defaultCodecs()
.maxInMemorySize(1024 * 1024))
// Filter to add bearer token to auth header before sending request
.filter((request, next) -> getToken(custId).map(setAuthHeader(request)).flatMap(next::exchange))
// Filter to send the request, and try again if it has an auth error
.filter((request, next) -> next.exchange(request).flatMap(clientResponse -> {
:::
return Mono.just(clientResponse);
})).build();
and
private ClientHttpConnector createWebClientWithTimeout() {
// create reactor netty HTTP client
HttpClient httpClient = HttpClient.newConnection()
.wiretap("reactor.netty.http.client.HttpClient",
LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL)
.compress(true)
.tcpConfiguration(tcpClient -> {
tcpClient = tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, linkedinConnectTimeoutInSeconds * 1000)
.doOnConnected(conn -> conn
.addHandlerLast(new ReadTimeoutHandler(linkedinReadTimeoutInSeconds, TimeUnit.SECONDS))
.addHandlerLast(new WriteTimeoutHandler(linkedinWriteTimeoutInSeconds, TimeUnit.SECONDS)));
return tcpClient;
});
// create a client http connector using above http client
return new ReactorClientHttpConnector(httpClient);
}
If we don't set logging.level.reactor.netty.http.client=debug, neither of these webclients log netty debug statements. If we set the debug parameter, both log the requests, the second one also logs request/response headers and bodies.

How to detect if RSocket connection is successfull?

I have the following program through which I can detect the connection failure i.e doBeforeRetry.
Can someone tell me how to detect the successful connection or reconnection. I want to integrate a Health Check program that monitors this connection, but I am unable to capture the event that informs the connections is successfull.
Thanks
requester = RSocketRequester.builder()
.rsocketConnector(connector -> {
connector.reconnect(Retry
.fixedDelay(Integer.MAX_VALUE,Duration.ofSeconds(1))
.doBeforeRetry(e-> System.out.println("doBeforeRetry===>"+e))
.doAfterRetry(e-> System.out.println("doAfterRetry===>"+e))
);
connector.payloadDecoder(PayloadDecoder.ZERO_COPY);
}
).dataMimeType(MediaType.APPLICATION_CBOR)
.rsocketStrategies(strategies)
.tcp("localhost", 7999);
I achieved the detection of successful connection or reconnection with the following approach.
Client Side (Connection initialization)
Mono<RSocketRequester> requester = Mono.just(RSocketRequester.builder()
.rsocketConnector(
// connector configuration goes here
)
.dataMimeType(MediaType.APPLICATION_CBOR)
.setupRoute("client-handshake")
.setupData("caller-name")
.tcp("localhost", 7999)));
One the server side
#ConnectMapping("client-handshake")
public void connect(RSocketRequester requester, #Payload String callerName) {
LOG.info("Client Connection Handshake: [{}]", callerName);
requester
.route("server-handshake")
.data("I am server")
.retrieveMono(Void.class)
.subscribe();
}
On the client side, when I receive the callback on the below method, I detect the connection is successfull.
#MessageMapping("server-handshake")
public Mono<ConsumerPreference> handshake(final String response){
LOG.info("Server Connection Handshake received : Server message [{}]", response.getCallerName());
connectionSuccess.set(true);
return Mono.empty();
}else{
throw new InitializationException("Invalid response message received from Server");
}
}
Additionally, created a application level heartbeat to ensure, the liveliness of the connection.
If you want to know if it's actually healthy, you should probably have a side task that is polling the health of the RSocket, by sending something like a custom ping protocol to your backend. You could time that and confirm that you have a healthy connection, record latencies and success/failures.

How to catch okhttp3 WebSocket network activity using okhttp3.Interceptor?

I have an okhttp3 (3.9.1) WebSocket instance and would like to view all it's network requests and responses. I tried to add some okhttp3.Interceptor instances to OkHttpClient instance before creating WebSocket on it but had no luck in viewing network activity. Here's sample code which demonstrates what I've tried to do:
package sample
import okhttp3.*
import java.io.IOException
import java.lang.Thread.sleep
fun main(args: Array<String>) {
val listener = object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket?, text: String?) {
println("Got server message: $text")
}
}
val dummyInterceptor = Interceptor { chain ->
val request = chain.request()
val response = chain.proceed(request)
println("Dummy interceptor fired!\n\nRequest: ${request.headers()}\nResponse: ${response.headers()}")
return#Interceptor response
}
val dummyNetworkInterceptor = Interceptor { chain ->
val request = chain.request()
val response = chain.proceed(request)
println("Dummy network interceptor fired!\n\nRequest: ${request.headers()}\nResponse: ${response.headers()}")
return#Interceptor response
}
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(dummyInterceptor)
.addNetworkInterceptor(dummyNetworkInterceptor)
.build()
val request = Request.Builder().url("ws://echo.websocket.org").build()
val webSocket = okHttpClient.newWebSocket(request, listener)
webSocket.send("Hello1!")
webSocket.send("Hello2!")
webSocket.send("Hello3!")
sleep(2000) //Just for this sample to ensure all WS requests done
println("\n\n\tSome network activity\n\n")
okHttpClient.newCall(Request.Builder().get().url("http://echo.websocket.org").build()).enqueue(object : Callback {
override fun onFailure(call: Call?, exc: IOException?) {
println("OnFailure: ${exc?.message}")
}
override fun onResponse(call: Call?, response: Response?) {
println("OnResponse: ${response?.headers()}")
}
})
}
I tried to dive into okhttp3 source code and didn't find any reason why any of my interceptors doesn't fire on WS requests but works perfectly for any OkHttpClient request.
Is it a bug in okhttp3 or am I doing something wrong or it's just not possible to monitor WS requests using okhttp3.Interceptor?
WebSocket calls made with OkHttp don't use the interceptor chains that HTTP calls do, therefore you can't monitor them through interceptors.
I've faced this issue before myself, and so I looked at the source code and found the following then:
The regular HTTP calls go through the getResponseWithInterceptorChain() method in the RealCall class, which quite clearly starts the chained call of interceptors for each request.
The okhttp3.internal.ws package that includes the implementation of the WebSocket handling contains no code related to interceptors.
And really, interceptors catching WebSocket requests wouldn't really make sense in the first place. The Request that you can obtain in an interceptor represents an HTTP request, which WebSocket messages are not.
It isn't possible at this point, there's a feature request open for OkHttp but it isn't getting much traction: https://github.com/square/okhttp/issues/4192

Resources