Search in sources :

Example 31 with WebClientResponse

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;
}
Also used : WebClientResponse(io.helidon.webclient.WebClientResponse) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ParticipantStatus(org.eclipse.microprofile.lra.annotation.ParticipantStatus) URI(java.net.URI)

Example 32 with WebClientResponse

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;
    }
}
Also used : ParticipantStatus(org.eclipse.microprofile.lra.annotation.ParticipantStatus) LRAStatus(org.eclipse.microprofile.lra.annotation.LRAStatus) WebClientResponse(io.helidon.webclient.WebClientResponse) ParticipantStatus(org.eclipse.microprofile.lra.annotation.ParticipantStatus) URI(java.net.URI)

Example 33 with WebClientResponse

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)));
    }
}
Also used : WebClientResponse(io.helidon.webclient.WebClientResponse) JsonObject(jakarta.json.JsonObject) Test(org.junit.jupiter.api.Test)

Example 34 with WebClientResponse

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));
}
Also used : WebClientResponse(io.helidon.webclient.WebClientResponse) JsonObject(jakarta.json.JsonObject) Test(org.junit.jupiter.api.Test)

Example 35 with WebClientResponse

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);
    }
}
Also used : WebClientResponse(io.helidon.webclient.WebClientResponse) Matchers.isEmptyOrNullString(org.hamcrest.Matchers.isEmptyOrNullString) URI(java.net.URI) WebClient(io.helidon.webclient.WebClient)

Aggregations

WebClientResponse (io.helidon.webclient.WebClientResponse)120 Test (org.junit.jupiter.api.Test)85 WebClientRequestBuilder (io.helidon.webclient.WebClientRequestBuilder)38 Headers (io.helidon.common.http.Headers)24 WebClient (io.helidon.webclient.WebClient)24 JsonObject (jakarta.json.JsonObject)22 Order (org.junit.jupiter.api.Order)16 TestMethodOrder (org.junit.jupiter.api.TestMethodOrder)16 Http (io.helidon.common.http.Http)15 DataChunk (io.helidon.common.http.DataChunk)10 CoreMatchers.containsString (org.hamcrest.CoreMatchers.containsString)8 Single (io.helidon.common.reactive.Single)7 WebServer (io.helidon.webserver.WebServer)7 Logger (java.util.logging.Logger)7 Context (io.helidon.common.context.Context)6 MediaType (io.helidon.common.http.MediaType)6 URI (java.net.URI)6 Optional (java.util.Optional)6 Contexts (io.helidon.common.context.Contexts)5 Multi (io.helidon.common.reactive.Multi)5