Search in sources :

Example 1 with UnknownRemoteException

use of com.palantir.conjure.java.api.errors.UnknownRemoteException in project conjure-java-runtime by palantir.

the class UnknownRemoteExceptionResponseHandlerTest method extractsIoExceptionForAllErrorCodes.

@Test
public void extractsIoExceptionForAllErrorCodes() {
    for (int code : ImmutableList.of(300, 400, 404, 500)) {
        UnknownRemoteException exception = decode(MediaType.APPLICATION_JSON, code, "body").get();
        assertThat(exception.getStatus()).isEqualTo(code);
        assertThat(exception.getBody()).isEqualTo("body");
        assertThat(exception.getMessage()).isEqualTo(String.format("Response status: %s", code));
    }
}
Also used : UnknownRemoteException(com.palantir.conjure.java.api.errors.UnknownRemoteException) Test(org.junit.Test)

Example 2 with UnknownRemoteException

use of com.palantir.conjure.java.api.errors.UnknownRemoteException in project conjure-java-runtime by palantir.

the class RemotingOkHttpCall method enqueueInternal.

private void enqueueInternal(Callback callback) {
    super.enqueue(new LeakedResponseClosingCallback(new Callback() {

        @Override
        public void onFailure(Call call, IOException exception) {
            if (isCanceled()) {
                callback.onFailure(call, exception);
                return;
            }
            urls.markAsFailed(request().url());
            // Fail call if backoffs are exhausted or if no retry URL can be determined.
            Optional<Duration> backoff = backoffStrategy.nextBackoff();
            if (!shouldRetry(exception, backoff)) {
                callback.onFailure(call, new SafeIoException("Failed to complete the request due to an IOException", exception, UnsafeArg.of("requestUrl", call.request().url().toString())));
                return;
            }
            Optional<HttpUrl> redirectTo = urls.redirectToNext(request().url());
            if (!redirectTo.isPresent()) {
                callback.onFailure(call, new SafeIoException("Failed to determine valid failover URL", exception, UnsafeArg.of("requestUrl", call.request().url().toString()), UnsafeArg.of("baseUrls", urls.getBaseUrls())));
                return;
            }
            retryIfAllowed(callback, call, exception, () -> {
                if (log.isInfoEnabled()) {
                    log.info("Retrying call after failure", SafeArg.of("backoffMillis", backoff.get().toMillis()), // format this value asynchronously.
                    SafeArg.of("backoffState", backoffStrategy.toString()), UnsafeArg.of("requestUrl", call.request().url().toString()), UnsafeArg.of("redirectToUrl", redirectTo.get().toString()), exception);
                }
                Tags.AttemptSpan nextAttempt = createNextAttempt();
                Request redirectedRequest = request().newBuilder().url(redirectTo.get()).tag(Tags.AttemptSpan.class, nextAttempt).build();
                RemotingOkHttpCall retryCall = client.newCallWithMutableState(redirectedRequest, backoffStrategy, maxNumRelocations - 1, Optional.of(call));
                scheduleExecution(backoff.get(), nextAttempt, retryCall, callback);
            });
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            urls.markAsSucceeded(request().url());
            // Relay successful responses
            if (response.code() / 100 <= 2) {
                callback.onResponse(call, response);
                return;
            }
            ResponseBody maybeResponseBody = response.body();
            // Buffer the response into a byte[] so that multiple handler can safely consume the body.
            // This consumes and closes the original response body.
            Supplier<Response> errorResponseSupplier;
            try {
                byte[] body = maybeResponseBody == null ? null : maybeResponseBody.bytes();
                // so error handlers can read the body without breaking subsequent handlers
                errorResponseSupplier = () -> buildFrom(response, body);
            } catch (IOException e) {
                onFailure(call, e);
                return;
            } finally {
                close(response);
            }
            // Handle to handle QoS situations: retry, failover, etc.
            Optional<QosException> qosError = qosHandler.handle(errorResponseSupplier.get());
            if (qosError.isPresent()) {
                qosError.get().accept(createQosVisitor(callback, call, errorResponseSupplier.get()));
                return;
            }
            // Handle responses that correspond to RemoteExceptions / SerializableErrors
            Optional<RemoteException> httpError = remoteExceptionHandler.handle(errorResponseSupplier.get());
            if (httpError.isPresent()) {
                callback.onFailure(call, new IoRemoteException(httpError.get()));
                return;
            }
            // Catch-all: handle all other responses
            Optional<UnknownRemoteException> unknownHttpError = unknownRemoteExceptionHandler.handle(errorResponseSupplier.get());
            if (unknownHttpError.isPresent()) {
                callback.onFailure(call, new IoUnknownRemoteException(unknownHttpError.get()));
                return;
            }
            callback.onFailure(call, new SafeIoException("Failed to handle request, this is an conjure-java-runtime bug."));
        }
    }));
}
Also used : QosException(com.palantir.conjure.java.api.errors.QosException) UnknownRemoteException(com.palantir.conjure.java.api.errors.UnknownRemoteException) SafeIoException(com.palantir.logsafe.exceptions.SafeIoException) Call(okhttp3.Call) Request(okhttp3.Request) Duration(java.time.Duration) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) HttpUrl(okhttp3.HttpUrl) ResponseBody(okhttp3.ResponseBody) Response(okhttp3.Response) Callback(okhttp3.Callback) FutureCallback(com.google.common.util.concurrent.FutureCallback) RemoteException(com.palantir.conjure.java.api.errors.RemoteException) UnknownRemoteException(com.palantir.conjure.java.api.errors.UnknownRemoteException)

Example 3 with UnknownRemoteException

use of com.palantir.conjure.java.api.errors.UnknownRemoteException in project dialogue by palantir.

the class DefaultClientsBlockingTest method testUnknownRemoteException.

@Test
public void testUnknownRemoteException() {
    UnknownRemoteException remoteException = new UnknownRemoteException(502, "Nginx broke");
    ListenableFuture<Object> failedFuture = Futures.immediateFailedFuture(remoteException);
    assertThatThrownBy(() -> DefaultClients.INSTANCE.block(failedFuture)).isInstanceOf(UnknownRemoteException.class).hasMessage("Response status: 502").satisfies(exception -> {
        assertThat(((UnknownRemoteException) exception).getBody()).isEqualTo("Nginx broke");
    });
}
Also used : UnknownRemoteException(com.palantir.conjure.java.api.errors.UnknownRemoteException) Test(org.junit.jupiter.api.Test)

Example 4 with UnknownRemoteException

use of com.palantir.conjure.java.api.errors.UnknownRemoteException in project atlasdb by palantir.

the class DefaultLockAndTimestampServiceFactory method createRawLeaderServices.

private static LockAndTimestampServices createRawLeaderServices(MetricsManager metricsManager, LeaderConfig leaderConfig, Consumer<Object> env, Supplier<LockService> lock, Supplier<ManagedTimestampService> time, UserAgent userAgent) {
    // Create local services, that may or may not end up being registered in an Consumer<Object>.
    LocalPaxosServices localPaxosServices = Leaders.createAndRegisterLocalServices(metricsManager, env, leaderConfig, userAgent);
    LeadershipCoordinator leadershipCoordinator = localPaxosServices.leadershipCoordinator();
    LockService localLock = AwaitingLeadershipProxy.newProxyInstance(LockService.class, lock, leadershipCoordinator);
    ManagedTimestampService managedTimestampProxy = AwaitingLeadershipProxy.newProxyInstance(ManagedTimestampService.class, time, leadershipCoordinator);
    // These facades are necessary because of the semantics of the JAX-RS algorithm (in particular, accepting
    // just the managed timestamp service will *not* work).
    TimestampService localTime = getTimestampFacade(managedTimestampProxy);
    TimestampManagementService localManagement = getTimestampManagementFacade(managedTimestampProxy);
    env.accept(localLock);
    env.accept(localTime);
    env.accept(localManagement);
    // Create remote services, that may end up calling our own local services.
    ImmutableServerListConfig serverListConfig = ImmutableServerListConfig.builder().servers(leaderConfig.leaders()).sslConfiguration(leaderConfig.sslConfiguration()).build();
    ServiceCreator creator = ServiceCreator.noPayloadLimiter(metricsManager, Refreshable.only(serverListConfig), userAgent, () -> RemotingClientConfigs.DEFAULT);
    LockService remoteLock = new RemoteLockServiceAdapter(creator.createService(NamespaceAgnosticLockRpcClient.class));
    TimestampService remoteTime = creator.createService(TimestampService.class);
    TimestampManagementService remoteManagement = creator.createService(TimestampManagementService.class);
    if (leaderConfig.leaders().size() == 1) {
        // Attempting to connect to ourself while processing a request can lead to deadlock if incoming request
        // volume is high, as all Jetty threads end up waiting for the timestamp server, and no threads remain to
        // actually handle the timestamp server requests. If we are the only single leader, we can avoid the
        // deadlock entirely; so use PingableLeader's getUUID() to detect this situation and eliminate the redundant
        // call.
        PingableLeader localPingableLeader = localPaxosServices.localPingableLeader();
        String localServerId = localPingableLeader.getUUID();
        PingableLeader remotePingableLeader = AtlasDbHttpClients.createProxy(ServiceCreator.createTrustContext(leaderConfig.sslConfiguration()), Iterables.getOnlyElement(leaderConfig.leaders()), PingableLeader.class, AuxiliaryRemotingParameters.builder().userAgent(userAgent).shouldRetry(true).shouldLimitPayload(true).shouldUseExtendedTimeout(false).build());
        // Determine asynchronously whether the remote services are talking to our local services.
        CompletableFuture<Boolean> useLocalServicesFuture = new CompletableFuture<>();
        TransactionManagers.runAsync.accept(() -> {
            int attemptsLeftBeforeLog = ATTEMPTS_BEFORE_LOGGING_FAILURE_TO_READ_REMOTE_TIMESTAMP_SERVER_ID;
            while (true) {
                try {
                    String remoteServerId = remotePingableLeader.getUUID();
                    useLocalServicesFuture.complete(localServerId.equals(remoteServerId));
                    return;
                } catch (ClientErrorException e) {
                    useLocalServicesFuture.complete(false);
                    return;
                } catch (UnknownRemoteException e) {
                    // manifest as ClientErrorExceptions.
                    if (400 <= e.getStatus() && e.getStatus() <= 499) {
                        useLocalServicesFuture.complete(false);
                        return;
                    }
                    attemptsLeftBeforeLog = logFailureToReadRemoteTimestampServerId(attemptsLeftBeforeLog, e);
                } catch (Throwable e) {
                    attemptsLeftBeforeLog = logFailureToReadRemoteTimestampServerId(attemptsLeftBeforeLog, e);
                }
                Uninterruptibles.sleepUninterruptibly(Duration.ofSeconds(1));
            }
        });
        // Create dynamic service proxies, that switch to talking directly to our local services if it turns out our
        // remote services are pointed at them anyway.
        LockService dynamicLockService = LocalOrRemoteProxy.newProxyInstance(LockService.class, localLock, remoteLock, useLocalServicesFuture);
        // Use managedTimestampProxy here to avoid local calls going through indirection.
        TimestampService dynamicTimeService = LocalOrRemoteProxy.newProxyInstance(TimestampService.class, managedTimestampProxy, remoteTime, useLocalServicesFuture);
        TimestampManagementService dynamicManagementService = LocalOrRemoteProxy.newProxyInstance(TimestampManagementService.class, managedTimestampProxy, remoteManagement, useLocalServicesFuture);
        return ImmutableLockAndTimestampServices.builder().lock(dynamicLockService).timestamp(dynamicTimeService).timestampManagement(dynamicManagementService).timelock(new LegacyTimelockService(dynamicTimeService, dynamicLockService, TransactionManagers.LOCK_CLIENT)).build();
    } else {
        return ImmutableLockAndTimestampServices.builder().lock(remoteLock).timestamp(remoteTime).timestampManagement(remoteManagement).timelock(new LegacyTimelockService(remoteTime, remoteLock, TransactionManagers.LOCK_CLIENT)).build();
    }
}
Also used : LegacyTimelockService(com.palantir.lock.impl.LegacyTimelockService) ImmutableServerListConfig(com.palantir.atlasdb.config.ImmutableServerListConfig) RemoteLockServiceAdapter(com.palantir.lock.client.RemoteLockServiceAdapter) LockRefreshingLockService(com.palantir.lock.client.LockRefreshingLockService) LockService(com.palantir.lock.LockService) ManagedTimestampService(com.palantir.timestamp.ManagedTimestampService) UnknownRemoteException(com.palantir.conjure.java.api.errors.UnknownRemoteException) LeadershipCoordinator(com.palantir.leader.proxy.LeadershipCoordinator) LocalPaxosServices(com.palantir.atlasdb.factory.Leaders.LocalPaxosServices) TimestampManagementService(com.palantir.timestamp.TimestampManagementService) CompletableFuture(java.util.concurrent.CompletableFuture) NamespaceAgnosticLockRpcClient(com.palantir.lock.NamespaceAgnosticLockRpcClient) PingableLeader(com.palantir.leader.PingableLeader) ClientErrorException(javax.ws.rs.ClientErrorException) TimestampService(com.palantir.timestamp.TimestampService) ManagedTimestampService(com.palantir.timestamp.ManagedTimestampService)

Example 5 with UnknownRemoteException

use of com.palantir.conjure.java.api.errors.UnknownRemoteException in project conjure-java-runtime by palantir.

the class RemotingOkHttpCall method execute.

/**
 * Process the call. If an IOException is encountered, mark the URL as failed, which indicates that it should be
 * avoided for subsequent calls (if {@link UrlSelector} was initialized with a positive
 * {@link ClientConfiguration#failedUrlCooldown()}.
 */
@Override
public Response execute() throws IOException {
    SettableFuture<Response> future = SettableFuture.create();
    enqueue(new Callback() {

        @Override
        public void onFailure(Call call, IOException exception) {
            if (!future.setException(exception)) {
                log.warn("Future has already completed", UnsafeArg.of("requestUrl", call.request().url().toString()), exception);
            }
        }

        @Override
        public void onResponse(Call call, Response response) {
            if (!future.set(response)) {
                close(response);
                log.warn("Future has already completed, closing the response", UnsafeArg.of("requestUrl", call.request().url().toString()));
            }
        }
    });
    try {
        // OkHttp call times out (, possibly after a number of retries).
        return future.get();
    } catch (InterruptedException e) {
        getDelegate().cancel();
        // Regardless of the cancel above, the call may have succeeded or is going to succeed, and we need to make
        // sure the response body is closed correctly in those cases.
        Futures.addCallback(future, ResponseClosingCallback.INSTANCE, MoreExecutors.directExecutor());
        Thread.currentThread().interrupt();
        throw new InterruptedIOException("Call cancelled via interruption");
    } catch (ExecutionException e) {
        getDelegate().cancel();
        if (e.getCause() instanceof IoRemoteException) {
            // TODO(rfink): Consider unwrapping the RemoteException at the Retrofit/Feign layer for symmetry, #626
            RemoteException wrappedException = ((IoRemoteException) e.getCause()).getWrappedException();
            RemoteException correctStackTrace = new RemoteException(wrappedException.getError(), wrappedException.getStatus());
            correctStackTrace.initCause(e);
            throw correctStackTrace;
        } else if (e.getCause() instanceof IoUnknownRemoteException) {
            UnknownRemoteException wrappedException = ((IoUnknownRemoteException) e.getCause()).getUnknownRemoteException();
            UnknownRemoteException correctStackTrace = new UnknownRemoteException(wrappedException.getStatus(), wrappedException.getBody());
            correctStackTrace.initCause(e);
            throw correctStackTrace;
        } else if (e.getCause() instanceof IOException) {
            throw (IOException) e.getCause();
        } else {
            throw new SafeIoException("Failed to execute call", e);
        }
    }
}
Also used : Call(okhttp3.Call) InterruptedIOException(java.io.InterruptedIOException) UnknownRemoteException(com.palantir.conjure.java.api.errors.UnknownRemoteException) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) Response(okhttp3.Response) Callback(okhttp3.Callback) FutureCallback(com.google.common.util.concurrent.FutureCallback) SafeIoException(com.palantir.logsafe.exceptions.SafeIoException) ExecutionException(java.util.concurrent.ExecutionException) RemoteException(com.palantir.conjure.java.api.errors.RemoteException) UnknownRemoteException(com.palantir.conjure.java.api.errors.UnknownRemoteException)

Aggregations

UnknownRemoteException (com.palantir.conjure.java.api.errors.UnknownRemoteException)6 FutureCallback (com.google.common.util.concurrent.FutureCallback)2 RemoteException (com.palantir.conjure.java.api.errors.RemoteException)2 SafeIoException (com.palantir.logsafe.exceptions.SafeIoException)2 IOException (java.io.IOException)2 InterruptedIOException (java.io.InterruptedIOException)2 Call (okhttp3.Call)2 Callback (okhttp3.Callback)2 Response (okhttp3.Response)2 Test (org.junit.jupiter.api.Test)2 ImmutableServerListConfig (com.palantir.atlasdb.config.ImmutableServerListConfig)1 LocalPaxosServices (com.palantir.atlasdb.factory.Leaders.LocalPaxosServices)1 QosException (com.palantir.conjure.java.api.errors.QosException)1 PingableLeader (com.palantir.leader.PingableLeader)1 LeadershipCoordinator (com.palantir.leader.proxy.LeadershipCoordinator)1 LockService (com.palantir.lock.LockService)1 NamespaceAgnosticLockRpcClient (com.palantir.lock.NamespaceAgnosticLockRpcClient)1 LockRefreshingLockService (com.palantir.lock.client.LockRefreshingLockService)1 RemoteLockServiceAdapter (com.palantir.lock.client.RemoteLockServiceAdapter)1 LegacyTimelockService (com.palantir.lock.impl.LegacyTimelockService)1