use of com.palantir.dialogue.Endpoint in project dialogue by palantir.
the class UserAgentEndpointChannelTest method testServiceNameIsNotValidConjureAgent.
@Test
public void testServiceNameIsNotValidConjureAgent() {
EndpointChannel channel = UserAgentEndpointChannel.create(delegate, new Endpoint() {
@Override
public void renderPath(Map<String, String> _params, UrlBuilder _url) {
}
@Override
public HttpMethod httpMethod() {
return HttpMethod.GET;
}
@Override
public String serviceName() {
return "Service_Name";
}
@Override
public String endpointName() {
return "endpoint";
}
@Override
public String version() {
return "4.5.6";
}
}, baseAgent);
// Special case: In IDEs, tests are run against classes (not JARs) and thus don't carry versions.
String dialogueVersion = Optional.ofNullable(Channel.class.getPackage().getImplementationVersion()).orElse("0.0.0");
channel.execute(request);
verify(delegate).execute(requestCaptor.capture());
assertThat(requestCaptor.getValue().headerParams().get("user-agent")).containsExactly("test-class/1.2.3 dialogue/" + dialogueVersion);
}
use of com.palantir.dialogue.Endpoint in project dialogue by palantir.
the class PinUntilErrorNodeSelectionStrategyChannel method maybeExecute.
@Override
public Optional<ListenableFuture<Response>> maybeExecute(Endpoint endpoint, Request request, LimitEnforcement limitEnforcement) {
int pin = currentPin.get();
PinChannel channel = nodeList.get(pin);
// n.b. StickyAttachments.maybeExecute uses the delegate PinChannel, which bypasses the FutureCallback
// instrumentation below on subsequent "sticky" requests.
Optional<ListenableFuture<Response>> maybeResponse = StickyAttachments.maybeAddStickyToken(channel, endpoint, request, limitEnforcement);
if (!maybeResponse.isPresent()) {
return Optional.empty();
}
DialogueFutures.addDirectCallback(maybeResponse.get(), new FutureCallback<>() {
@Override
public void onSuccess(Response response) {
// even if a couple of them get rate limited in the middle.
if (Responses.isServerErrorRange(response) || (Responses.isQosStatus(response) && !Responses.isTooManyRequests(response))) {
OptionalInt next = incrementHostIfNecessary(pin);
instrumentation.receivedErrorStatus(pin, channel, response, next);
} else {
instrumentation.successfulResponse(channel.stableIndex());
}
}
@Override
public void onFailure(Throwable throwable) {
OptionalInt next = incrementHostIfNecessary(pin);
instrumentation.receivedThrowable(pin, channel, throwable, next);
}
});
return maybeResponse;
}
use of com.palantir.dialogue.Endpoint in project dialogue by palantir.
the class QueuedChannel method scheduleNextTask.
/**
* Get the next call and attempt to execute it. If it is runnable, wire up the underlying future to the one
* previously returned to the caller. If it is not runnable, add it back into the queue. Returns true if more
* tasks may be able to be scheduled, and false otherwise.
*/
private boolean scheduleNextTask() {
DeferredCall queueHead = queuedCalls.poll();
if (queueHead == null) {
return false;
}
SettableFuture<Response> queuedResponse = queueHead.response();
// request will be quickly cancelled in that case.
if (queuedResponse.isDone()) {
decrementQueueSize();
queueHead.span().complete();
queueHead.timer().stop();
return true;
}
try (CloseableSpan ignored = queueHead.span().attach()) {
Endpoint endpoint = queueHead.endpoint();
Optional<ListenableFuture<Response>> maybeResponse = delegate.maybeExecute(endpoint, queueHead.request(), DO_NOT_SKIP_LIMITS);
if (maybeResponse.isPresent()) {
decrementQueueSize();
ListenableFuture<Response> response = maybeResponse.get();
queueHead.span().complete();
queueHead.timer().stop();
DialogueFutures.addDirectCallback(response, new ForwardAndSchedule(queuedResponse));
DialogueFutures.addDirectListener(queuedResponse, () -> {
if (queuedResponse.isCancelled()) {
// Currently cancel(false) will be converted to cancel(true)
if (!response.cancel(true) && log.isDebugEnabled()) {
log.debug("Failed to cancel delegate response, it should be reported by ForwardAndSchedule " + "logging", SafeArg.of("channel", channelName), SafeArg.of("service", endpoint.serviceName()), SafeArg.of("endpoint", endpoint.endpointName()));
}
}
});
return true;
} else {
if (!queuedCalls.offerFirst(queueHead)) {
// Should never happen, ConcurrentLinkedDeque has no maximum size
log.error("Failed to add an attempted call back to the deque", SafeArg.of("channel", channelName), SafeArg.of("service", endpoint.serviceName()), SafeArg.of("endpoint", endpoint.endpointName()));
decrementQueueSize();
queueHead.timer().stop();
if (!queuedResponse.setException(new SafeRuntimeException("Failed to req-queue request", SafeArg.of("channel", channelName), SafeArg.of("service", endpoint.serviceName()), SafeArg.of("endpoint", endpoint.endpointName())))) {
if (log.isDebugEnabled()) {
log.debug("Queued response has already been completed", SafeArg.of("channel", channelName), SafeArg.of("service", endpoint.serviceName()), SafeArg.of("endpoint", endpoint.endpointName()));
}
}
}
return false;
}
}
}
use of com.palantir.dialogue.Endpoint in project dialogue by palantir.
the class QueuedChannel method maybeExecute.
/**
* Enqueues and tries to schedule as many queued tasks as possible.
*/
@VisibleForTesting
@SuppressWarnings("PreferJavaTimeOverload")
Optional<ListenableFuture<Response>> maybeExecute(Endpoint endpoint, Request request) {
// Queuing adds contention between threads and should be avoided unless we need to shed load.
if (queueSizeEstimate.get() <= 0) {
Optional<ListenableFuture<Response>> maybeResult = delegate.maybeExecute(endpoint, request, DO_NOT_SKIP_LIMITS);
if (maybeResult.isPresent()) {
ListenableFuture<Response> result = maybeResult.get();
DialogueFutures.addDirectListener(result, this::onCompletion);
// While the queue was avoid, this is equivalent to spending zero time on the queue.
if (shouldRecordQueueMetrics) {
queuedTime.update(0, TimeUnit.NANOSECONDS);
}
return maybeResult;
}
}
// maybeExecute may take sufficiently long that other requests could be queued.
if (queueSizeEstimate.get() >= maxQueueSize) {
return Optional.empty();
}
shouldRecordQueueMetrics = true;
DeferredCall components = DeferredCall.builder().endpoint(endpoint).request(request).response(SettableFuture.create()).span(DetachedSpan.start("Dialogue-request-enqueued")).timer(queuedTime.time()).build();
if (!queuedCalls.offer(components)) {
// Should never happen, ConcurrentLinkedDeque has no maximum size
return Optional.empty();
}
int newSize = incrementQueueSize();
if (log.isDebugEnabled()) {
log.debug("Request queued {} on channel {}", SafeArg.of("queueSize", newSize), SafeArg.of("channelName", channelName));
}
schedule();
return Optional.of(components.response());
}
use of com.palantir.dialogue.Endpoint in project dialogue by palantir.
the class SimulationTest method slowdown_and_error_thresholds.
@SimulationCase
public void slowdown_and_error_thresholds(Strategy strategy) {
Endpoint getEndpoint = SimulationUtils.endpoint("endpoint", HttpMethod.GET);
int errorThreshold = 40;
int slowdownThreshold = 30;
servers = servers(SimulationServer.builder().serverName("fast").simulation(simulation).handler(getEndpoint, h -> h.respond200UntilCapacity(500, errorThreshold).linearResponseTime(Duration.ofMillis(600), slowdownThreshold)).build(), SimulationServer.builder().serverName("medium").simulation(simulation).handler(getEndpoint, h -> h.respond200UntilCapacity(500, errorThreshold).linearResponseTime(Duration.ofMillis(800), slowdownThreshold)).build(), SimulationServer.builder().serverName("slightly_slow").simulation(simulation).handler(getEndpoint, h -> h.respond200UntilCapacity(500, errorThreshold).linearResponseTime(Duration.ofMillis(1000), slowdownThreshold)).build());
st = strategy;
result = Benchmark.builder().simulation(simulation).requestsPerSecond(500).sendUntil(Duration.ofSeconds(20)).clients(10, _i -> strategy.getChannel(simulation, servers)).endpoints(getEndpoint).abortAfter(Duration.ofMinutes(10)).run();
}
Aggregations