use of io.helidon.webclient.WebClientResponse in project helidon by oracle.
the class Participant method sendComplete.
boolean sendComplete(Lra lra) {
Optional<URI> endpointURI = getCompleteURI();
for (AtomicInteger i = new AtomicInteger(0); i.getAndIncrement() < SYNCHRONOUS_RETRY_CNT; ) {
if (!sendingStatus.compareAndSet(SendingStatus.NOT_SENDING, SendingStatus.SENDING))
return false;
LOGGER.log(Level.FINE, () -> "Sending complete, sync retry: " + i.get() + ", status: " + status.get().name() + " statusUri: " + getStatusURI().map(URI::toASCIIString).orElse(null));
WebClientResponse response = null;
try {
if (status.get().isFinal()) {
return true;
// call for client status only on retries and when status uri is known
} else if (!status.get().equals(Status.ACTIVE) && getStatusURI().isPresent()) {
// If the participant does not support idempotency then it MUST be able to report its status
// by annotating one of the methods with the @Status annotation which should report the status
// in case we can't retrieve status from participant just retry n times
ParticipantStatus reportedClientStatus = retrieveStatus(lra, Completing).orElse(null);
if (reportedClientStatus == Completed) {
LOGGER.log(Level.INFO, "Participant reports it is completed.");
status.set(Status.COMPLETED);
return true;
} else if (reportedClientStatus == FailedToComplete) {
LOGGER.log(Level.INFO, "Participant reports it failed to complete.");
status.set(Status.FAILED_TO_COMPLETE);
return true;
} else if (reportedClientStatus == Active) {
// last call didn't reach participant, try call again
} else if (reportedClientStatus == Completing) {
LOGGER.log(Level.INFO, "Participant reports it is still completing.");
status.set(Status.CLIENT_COMPLETING);
return false;
} else if (remainingCloseAttempts.decrementAndGet() <= 0) {
LOGGER.log(Level.INFO, "Participant didnt report final status after {0} status call retries.", new Object[] { RETRY_CNT });
status.set(Status.FAILED_TO_COMPLETE);
return true;
} else {
// Unknown status, lets try in next recovery cycle
return false;
}
}
response = getWebClient(endpointURI.get()).put().headers(lra.headers()).submit(LRAStatus.Closed.name()).await(timeout, TimeUnit.MILLISECONDS);
switch(response.status().code()) {
// complete or compensated
case 200:
case 410:
status.set(Status.COMPLETED);
return true;
// retryable
case 202:
// Still completing, check with @Status later
this.status.set(Status.CLIENT_COMPLETING);
return false;
case 409:
case 404:
case 503:
default:
throw new Exception(response.status().code() + " " + response.status().reasonPhrase());
}
} catch (Exception e) {
LOGGER.log(Level.WARNING, e, () -> "Can't reach participant's complete endpoint: " + endpointURI.map(URI::toASCIIString).orElse("unknown"));
if (remainingCloseAttempts.decrementAndGet() <= 0) {
LOGGER.log(Level.WARNING, "Failed to complete participant of LRA {0} {1} {2}", new Object[] { lra.lraId(), this.getCompleteURI(), e.getMessage() });
status.set(Status.FAILED_TO_COMPLETE);
} else {
status.set(Status.COMPLETING);
}
} finally {
Optional.ofNullable(response).ifPresent(WebClientResponse::close);
sendingStatus.set(SendingStatus.NOT_SENDING);
}
}
return false;
}
use of io.helidon.webclient.WebClientResponse in project helidon by oracle.
the class Participant method retrieveStatus.
Optional<ParticipantStatus> retrieveStatus(Lra lra, ParticipantStatus inProgressStatus) {
URI statusURI = this.getStatusURI().get();
try {
WebClientResponse response = getWebClient(statusURI).get().headers(h -> {
// Dont send parent!
h.add(LRA_HTTP_CONTEXT_HEADER, lra.lraContextId());
h.add(LRA_HTTP_RECOVERY_HEADER, lra.lraContextId() + "/recovery");
h.add(LRA_HTTP_ENDED_CONTEXT_HEADER, lra.lraContextId());
return h;
}).request().await(timeout, TimeUnit.MILLISECONDS);
int code = response.status().code();
switch(code) {
case 202:
return Optional.of(inProgressStatus);
case // GONE
410:
// Completing -> FailedToComplete ...
return status.get().failedFinalStatus();
case 503:
case 500:
throw new IllegalStateException(String.format("Client reports unexpected status %s %s, " + "current participant state is %s, " + "lra: %s " + "status uri: %s", code, response.content().as(String.class), status.get(), lra.lraId(), statusURI.toASCIIString()));
default:
ParticipantStatus reportedStatus = valueOf(response.content().as(String.class).await());
Status currentStatus = status.get();
if (currentStatus.validateNextStatus(reportedStatus)) {
return Optional.of(reportedStatus);
} else {
LOGGER.log(Level.WARNING, "Client reports unexpected status {0} {1}, " + "current participant state is {2}, " + "lra: {3} " + "status uri: {4}", new Object[] { code, reportedStatus, currentStatus, lra.lraId(), statusURI.toASCIIString() });
return Optional.empty();
}
}
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Error when getting participant status. " + statusURI, e);
// skip dependent compensation call, another retry with status call might be luckier
throw e;
}
}
use of io.helidon.webclient.WebClientResponse in project helidon by oracle.
the class TestServer method checkVendorURL.
@Test
public void checkVendorURL() {
WebClientResponse response = webClientBuilder.build().get().accept(MediaType.APPLICATION_JSON).path("metrics/vendor").submit().await(CLIENT_TIMEOUT);
assertThat("Normal metrics/vendor URL HTTP response", response.status().code(), is(200));
JsonObject metrics = response.content().as(JsonObject.class).await(CLIENT_TIMEOUT);
if (System.getenv("MP_METRICS_TAGS") == null) {
// MP_METRICS_TAGS causes metrics to add tags to metric IDs. Just do this check in the simple case, without tags.
assertThat("Vendor metrics requests.count in returned entity", metrics.containsKey("requests.count"), is(true));
assertThat("Vendor metrics requests.meter in returned entity", metrics.containsKey("requests.meter"), is(true));
// Even accesses to the /metrics endpoint should affect the metrics. Make sure.
int count = metrics.getInt("requests.count");
assertThat("requests.count", count, is(greaterThan(0)));
JsonObject meter = metrics.getJsonObject("requests.meter");
int meterCount = meter.getInt("count");
assertThat("requests.meter count", meterCount, is(greaterThan(0)));
double meterRate = meter.getJsonNumber("meanRate").doubleValue();
assertThat("requests.meter meanRate", meterRate, is(greaterThan(0.0)));
}
}
use of io.helidon.webclient.WebClientResponse in project helidon by oracle.
the class TestServer method checkNormalURL.
@Test
public void checkNormalURL() throws ExecutionException, InterruptedException {
WebClientResponse response = webClientBuilder.build().get().accept(MediaType.APPLICATION_JSON).path("metrics").submit().await(CLIENT_TIMEOUT);
assertThat("Normal metrics URL HTTP response", response.status().code(), is(200));
JsonObject metrics = response.content().as(JsonObject.class).await(CLIENT_TIMEOUT);
assertThat("Vendor metrics in returned entity", metrics.containsKey("vendor"), is(true));
}
use of io.helidon.webclient.WebClientResponse in project helidon by oracle.
the class LoadBalancedCoordinatorTest method waitForRecovery.
private void waitForRecovery(URI lraId) {
URI coordinatorPath = coordinatorPath(lraId);
for (int i = 0; i < 10; i++) {
WebClient client = WebClient.builder().baseUri(coordinatorPath).build();
WebClientResponse response = client.get().path("recovery").submit().await(TIMEOUT_SEC, TimeUnit.SECONDS);
String recoveringLras = response.content().as(String.class).await(TIMEOUT_SEC, TimeUnit.SECONDS);
response.close();
if (!recoveringLras.contains(lraId.toASCIIString())) {
LOGGER.fine("LRA is no longer among those recovering " + lraId.toASCIIString());
// intended LRA is not longer among those recovering
break;
}
LOGGER.fine("Waiting for recovery attempt #" + i + " LRA is still waiting: " + recoveringLras);
}
}
Aggregations