use of com.palantir.dialogue.Response in project dialogue by palantir.
the class DialogueClientsTest method getStickyChannels_live_reloads_nicely.
@Test
void getStickyChannels_live_reloads_nicely() {
SettableRefreshable<ServicesConfigBlock> refreshable = Refreshable.create(scb);
StickyChannelFactory stickyChannels = DialogueClients.create(refreshable).withUserAgent(TestConfigurations.AGENT).withMaxNumRetries(0).getStickyChannels("zero-uris-service");
ListenableFuture<Response> future = stickyChannels.getStickyChannel().execute(TestEndpoint.POST, Request.builder().build());
assertThatThrownBy(future::get).describedAs("Nice error message when service exists but has zero uris").hasCauseInstanceOf(SafeIllegalStateException.class).hasMessageContaining("Service not configured");
refreshable.update(ServicesConfigBlock.builder().from(scb).putServices("zero-uris-service", PartialServiceConfiguration.builder().addUris("https://live-reloaded-uri-appeared").build()).build());
ListenableFuture<Response> future2 = stickyChannels.getStickyChannel().execute(TestEndpoint.POST, Request.builder().build());
assertThatThrownBy(future2::get).describedAs("Made a real network call").hasCauseInstanceOf(UnknownHostException.class);
}
use of com.palantir.dialogue.Response in project dialogue by palantir.
the class ApacheHttpClientBlockingChannel method execute.
@Override
public Response execute(Endpoint endpoint, Request request) throws IOException {
// Create base request given the URL
URL target = baseUrl.render(endpoint, request);
ClassicRequestBuilder builder = ClassicRequestBuilder.create(endpoint.httpMethod().name()).setUri(target.toString());
// Fill headers
request.headerParams().forEach(builder::addHeader);
if (request.body().isPresent()) {
Preconditions.checkArgument(endpoint.httpMethod() != HttpMethod.GET, "GET endpoints must not have a request body");
Preconditions.checkArgument(endpoint.httpMethod() != HttpMethod.HEAD, "HEAD endpoints must not have a request body");
Preconditions.checkArgument(endpoint.httpMethod() != HttpMethod.OPTIONS, "OPTIONS endpoints must not have a request body");
RequestBody body = request.body().get();
setBody(builder, body);
} else if (requiresEmptyBody(endpoint)) {
builder.setEntity(EmptyHttpEntity.INSTANCE);
}
long startTime = System.nanoTime();
try {
HttpClientContext context = HttpClientContext.create();
CloseableHttpResponse httpClientResponse = client.apacheClient().execute(builder.build(), context);
// Defensively ensure that resources are closed if failures occur within this block,
// for example HttpClientResponse allocation may throw an OutOfMemoryError.
boolean close = true;
try {
Response dialogueResponse = new HttpClientResponse(client, httpClientResponse, context);
Response leakDetectingResponse = responseLeakDetector.wrap(dialogueResponse, endpoint);
close = false;
return leakDetectingResponse;
} finally {
if (close) {
httpClientResponse.close();
}
}
} catch (ConnectTimeoutException e) {
// cleaner metrics.
throw new SafeConnectTimeoutException(e, failureDiagnosticArgs(endpoint, request, startTime));
} catch (NoHttpResponseException e) {
// NoHttpResponseException may be thrown immediately when a request is sent if a pooled persistent
// connection has been closed by the target server, or an intermediate proxy. In this case it's
// important that we retry the request with a fresh connection.
// The other possibility is that a remote server or proxy may time out an active request due
// to inactivity and close the connection without a response, in this case the request mustn't
// be retried.
// We attempt to differentiate these two cases based on request duration, we expect most of
// the prior case to occur within a couple milliseconds, however we must use a larger value
// to account for large garbage collections.
long durationNanos = System.nanoTime() - startTime;
Arg<?>[] diagnosticArgs = failureDiagnosticArgs(endpoint, request, startTime);
if (durationNanos < TimeUnit.SECONDS.toNanos(5)) {
e.addSuppressed(new Diagnostic(diagnosticArgs));
throw e;
}
throw new SafeSocketTimeoutException("Received a NoHttpResponseException", e, diagnosticArgs);
} catch (Throwable t) {
// We can't wrap all potential exception types, that would cause the failure to lose some amount of type
// information. Instead, we add a suppressed throwable with no stack trace which acts as a courier
// for our diagnostic information, ensuring it can be recorded in the logs.
t.addSuppressed(new Diagnostic(failureDiagnosticArgs(endpoint, request, startTime)));
throw t;
}
}
use of com.palantir.dialogue.Response in project dialogue by palantir.
the class BlockingChannelAdapterTest method testSuccessful.
@Test
public void testSuccessful() {
CountDownLatch latch = new CountDownLatch(1);
Channel channel = BlockingChannelAdapter.of((_endpoint, _request) -> {
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return stubResponse;
}, executor);
ListenableFuture<Response> result = channel.execute(TestEndpoint.POST, Request.builder().build());
assertThat(result).isNotDone();
latch.countDown();
Awaitility.waitAtMost(Duration.ofSeconds(3)).untilAsserted(() -> {
assertThat(result).isDone();
assertThat(result.get()).isSameAs(stubResponse);
});
}
use of com.palantir.dialogue.Response in project dialogue by palantir.
the class BlockingChannelAdapterTest method testAlreadyShutdown.
@Test
void testAlreadyShutdown() {
executor.shutdown();
BlockingChannel delegate = mock(BlockingChannel.class);
Channel channel = BlockingChannelAdapter.of(delegate, executor);
ListenableFuture<Response> future = channel.execute(TestEndpoint.POST, Request.builder().build());
assertThat(future).isDone();
assertThatThrownBy(future::get).isInstanceOf(ExecutionException.class).hasCauseInstanceOf(RejectedExecutionException.class);
}
use of com.palantir.dialogue.Response in project dialogue by palantir.
the class BlockingChannelAdapterTest method testCancel.
@Test
public void testCancel() throws InterruptedException {
CountDownLatch channelLatch = new CountDownLatch(1);
CountDownLatch returnLatch = new CountDownLatch(1);
AtomicBoolean invocationInterrupted = new AtomicBoolean();
Response response = mock(Response.class);
Channel channel = BlockingChannelAdapter.of((_endpoint, _request) -> {
channelLatch.countDown();
Uninterruptibles.awaitUninterruptibly(returnLatch);
invocationInterrupted.set(Thread.currentThread().isInterrupted());
return response;
}, executor);
ListenableFuture<Response> result = channel.execute(TestEndpoint.POST, Request.builder().build());
channelLatch.await();
assertThat(result.cancel(true)).isTrue();
assertThat(result).isCancelled();
// Allow the channel to complete
returnLatch.countDown();
Awaitility.waitAtMost(Duration.ofSeconds(3)).untilAsserted(() -> verify(response).close());
assertThat(invocationInterrupted).isTrue();
}
Aggregations