![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.druid.rpc.ServiceClient Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.rpc;
import com.google.common.util.concurrent.ListenableFuture;
import org.apache.druid.common.guava.FutureUtils;
import org.apache.druid.java.util.http.client.HttpClient;
import org.apache.druid.java.util.http.client.response.HttpResponseHandler;
import org.apache.druid.rpc.indexing.OverlordClient;
import java.util.concurrent.ExecutionException;
/**
* Mid-level client that provides an API similar to low-level {@link HttpClient}, but accepts {@link RequestBuilder}
* instead of {@link org.apache.druid.java.util.http.client.Request}, and internally handles service location
* and retries.
*
* In most cases, this client is further wrapped in a high-level client like
* {@link OverlordClient}.
*/
public interface ServiceClient
{
long MAX_REDIRECTS = 3;
/**
* Perform a request asynchronously.
*
* Unlike {@link HttpClient#go}, the provided "handler" is only used for 2xx responses.
*
* Response codes 1xx, 4xx, and 5xx are retried with backoff according to the client's {@link ServiceRetryPolicy}.
* If attempts are exhausted, the future will fail with {@link RpcException} containing the most recently
* encountered error.
*
* Redirects from 3xx responses are followed up to a chain length of {@link #MAX_REDIRECTS} and do not consume
* attempts. Redirects are validated against the targets returned by {@link ServiceLocator}: the client will only
* follow redirects to targets that appear in {@link ServiceLocations}. If the client encounters a redirect to an
* unknown target, or if a redirect loop or self-redirect is detected, it is treated as an unavailable service and
* an attempt is consumed.
*
* If the service is unavailable at the time an attempt is made, the client will automatically retry based on
* {@link ServiceRetryPolicy#retryNotAvailable()}. If true, an attempt is consumed and the client will try to locate
* the service again on the next attempt. If false, the call immediately returns {@link ServiceNotAvailableException}.
*
* If an exception occurs midstream after an OK HTTP response (2xx) then the behavior depends on the handler. If
* the handler has not yet returned a finished object, the service client will automatically retry based on the
* provided {@link ServiceRetryPolicy}. On the other hand, if the handler has returned a finished object, the
* service client will not retry. Behavior in this case is up to the caller, who will have already received the
* finished object as the future's resolved value.
*
* Resolves to {@link HttpResponseException} if the final attempt failed due to a non-OK HTTP server response.
*
* Resolves to {@link ServiceNotAvailableException} if the final attempt failed because the service was not
* available (i.e. if the locator returned an empty set of locations).
*
* Resolves to {@link ServiceClosedException} if the final attempt failed because the service was closed. This is
* different from not available: generally, "not available" is a temporary condition whereas "closed" is a
* permanent condition.
*/
ListenableFuture asyncRequest(
RequestBuilder requestBuilder,
HttpResponseHandler handler
);
/**
* Perform a request synchronously.
*
* Same behavior as {@link #asyncRequest}, except the result is returned synchronously. Any exceptions from the
* underlying service call are wrapped in an ExecutionException.
*/
default FinalType request(
RequestBuilder requestBuilder,
HttpResponseHandler handler
) throws InterruptedException, ExecutionException
{
// Cancel the future if we are interrupted. Nobody else is waiting for it.
return FutureUtils.get(asyncRequest(requestBuilder, handler), true);
}
/**
* Returns a copy of this client with a different {@link ServiceRetryPolicy}.
*/
ServiceClient withRetryPolicy(ServiceRetryPolicy retryPolicy);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy