All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.journalkeeper.core.client.RemoteClientRpc Maven / Gradle / Ivy

There is a newer version: 0.1.11
Show newest version
/**
 * Licensed 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 io.journalkeeper.core.client; import io.journalkeeper.core.api.ClusterConfiguration; import io.journalkeeper.exceptions.NoLeaderException; import io.journalkeeper.exceptions.NotLeaderException; import io.journalkeeper.exceptions.RequestTimeoutException; import io.journalkeeper.exceptions.ServerBusyException; import io.journalkeeper.exceptions.ServerNotFoundException; import io.journalkeeper.exceptions.TransportException; import io.journalkeeper.rpc.BaseResponse; import io.journalkeeper.rpc.LeaderResponse; import io.journalkeeper.rpc.client.ClientServerRpc; import io.journalkeeper.rpc.client.ClientServerRpcAccessPoint; import io.journalkeeper.rpc.client.GetServersResponse; import io.journalkeeper.utils.event.EventWatcher; import io.journalkeeper.utils.retry.CheckRetry; import io.journalkeeper.utils.retry.CompletableRetry; import io.journalkeeper.utils.retry.RandomDestinationSelector; import io.journalkeeper.utils.retry.RetryPolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; /** * @author LiYue * Date: 2019-09-09 */ public class RemoteClientRpc implements ClientRpc { private static final Logger logger = LoggerFactory.getLogger(RemoteClientRpc.class); private final ClientServerRpcAccessPoint clientServerRpcAccessPoint; private final CompletableRetry completableRetry; private final RandomDestinationSelector uriSelector; private final ClientCheckRetry clientCheckRetry = new ClientCheckRetry(); private final Executor executor; private final ScheduledExecutorService scheduledExecutor; private URI leaderUri = null; private URI preferredServer = null; public RemoteClientRpc(List servers, ClientServerRpcAccessPoint clientServerRpcAccessPoint, RetryPolicy retryPolicy, Executor executor, ScheduledExecutorService scheduledExecutor) { this.executor = executor; this.scheduledExecutor = scheduledExecutor; if (servers == null || servers.isEmpty()) { throw new IllegalArgumentException("Argument servers can not be empty!"); } this.clientServerRpcAccessPoint = clientServerRpcAccessPoint; uriSelector = new PreferredServerRandomUriSelector(servers); completableRetry = new CompletableRetry<>(retryPolicy, uriSelector); } @Override public final CompletableFuture invokeClientServerRpc(CompletableRetry.RpcInvoke invoke) { return completableRetry.retry(uri -> invoke.invoke(clientServerRpcAccessPoint.getClintServerRpc(uri)), clientCheckRetry, executor, scheduledExecutor); } @Override public CompletableFuture invokeClientServerRpc(URI uri, CompletableRetry.RpcInvoke invoke) { return completableRetry.retry(uri1 -> invoke.invoke(clientServerRpcAccessPoint.getClintServerRpc(uri1)), clientCheckRetry, uri, executor, scheduledExecutor); } @Override public final CompletableFuture invokeClientLeaderRpc(CompletableRetry.RpcInvoke invoke) { return invokeClientServerRpc(rpc -> unSetLeaderUriWhenLeaderRpcFailed(getCachedLeaderRpc(rpc).thenCompose(invoke::invoke)) ); } private CompletableFuture unSetLeaderUriWhenLeaderRpcFailed(CompletableFuture future) { return future .exceptionally(e -> { this.leaderUri = null; throw new CompletionException(e); }).thenApply(response -> { if (!response.success()) { this.leaderUri = null; } return response; }); } private CompletableFuture getCachedLeaderRpc(ClientServerRpc clientServerRpc) { CompletableFuture leaderUriFuture = new CompletableFuture<>(); if (this.leaderUri == null) { GetServersResponse getServersResponse = null; try { getServersResponse = clientServerRpc.getServers().get(); } catch (Throwable e) { Throwable ex = e instanceof ExecutionException ? e.getCause() : e; leaderUriFuture = new CompletableFuture<>(); leaderUriFuture.completeExceptionally(ex); } if (null != getServersResponse && getServersResponse.success()) { ClusterConfiguration clusterConfiguration = getServersResponse.getClusterConfiguration(); if (null != clusterConfiguration) { this.leaderUri = clusterConfiguration.getLeader(); } } } if (this.leaderUri != null) { leaderUriFuture.complete(leaderUri); } else if (!leaderUriFuture.isDone()) { leaderUriFuture.completeExceptionally(new NoLeaderException()); } // logger.info("Current leader in client: {}", leaderUri); return leaderUriFuture.thenApply(clientServerRpcAccessPoint::getClintServerRpc); } @Override public void stop() { this.clientServerRpcAccessPoint.stop(); } @Override public URI getPreferredServer() { return preferredServer; } @Override public void setPreferredServer(URI preferredServer) { this.preferredServer = preferredServer; } @Override public void updateServers(List servers) { uriSelector.setAllDestinations(servers); } @Override public void watch(EventWatcher eventWatcher) { completableRetry.retry(uri -> { clientServerRpcAccessPoint.getClintServerRpc(uri) .watch(eventWatcher); return CompletableFuture.completedFuture(null); }, clientCheckRetry, executor, scheduledExecutor); } @Override public void unWatch(EventWatcher eventWatcher) { completableRetry.retry(uri -> { clientServerRpcAccessPoint.getClintServerRpc(uri).unWatch(eventWatcher); return CompletableFuture.completedFuture(null); }, clientCheckRetry, executor, scheduledExecutor); } private class ClientCheckRetry implements CheckRetry { @Override public boolean checkException(Throwable exception) { try { logger.debug("Rpc exception: {}-{}", exception.getClass().getCanonicalName(), exception.getMessage()); throw exception; } catch (RequestTimeoutException | ServerBusyException | TransportException | ServerNotFoundException ne) { return true; } catch (NoLeaderException ne) { leaderUri = null; return true; } catch (NotLeaderException ne) { leaderUri = ne.getLeader(); return true; } catch (Throwable ignored) { } return false; } @Override public boolean checkResult(BaseResponse response) { switch (response.getStatusCode()) { case NOT_LEADER: leaderUri = ((LeaderResponse) response).getLeader(); logger.info("{} failed, cause: {}, Retry...", response.getClass().getName(), response.errorString()); return true; case TIMEOUT: case SERVER_BUSY: case RETRY_LATER: case TRANSPORT_FAILED: case EXCEPTION: logger.info("{} failed, cause: {}, Retry...", response.getClass().getName(), response.errorString()); return true; case SUCCESS: return false; default: logger.warn("{} failed, cause: {}!", response.getClass().getName(), response.errorString()); return false; } } } private class PreferredServerRandomUriSelector extends RandomDestinationSelector { PreferredServerRandomUriSelector(Collection allDestinations) { super(allDestinations); } @Override public URI select(Set usedDestinations) { if ((null == usedDestinations || usedDestinations.isEmpty()) && null != preferredServer) { return preferredServer; } else { return super.select(usedDestinations); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy