All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.ydb.core.impl.call.UnaryCall Maven / Gradle / Ivy

package tech.ydb.core.impl.call;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;

import javax.annotation.Nullable;

import com.google.protobuf.Message;
import com.google.protobuf.TextFormat;
import io.grpc.ClientCall;
import io.grpc.Metadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import tech.ydb.core.Issue;
import tech.ydb.core.Result;
import tech.ydb.core.Status;
import tech.ydb.core.StatusCode;
import tech.ydb.core.grpc.GrpcStatuses;
import tech.ydb.core.grpc.GrpcTransport;

/**
 *
 * @author Aleksandr Gorshenin
 * @param  type of call argument
 * @param  type of call return
 */
public class UnaryCall extends ClientCall.Listener {
    private static final Logger logger = LoggerFactory.getLogger(GrpcTransport.class);

    private static final Status NO_VALUE = Status.of(StatusCode.CLIENT_INTERNAL_ERROR)
            .withIssues(Issue.of("No value received for gRPC unary call", Issue.Severity.ERROR));

    private static final Status MULTIPLY_VALUES = Status.of(StatusCode.CLIENT_INTERNAL_ERROR)
            .withIssues(Issue.of("More than one value received for gRPC unary call", Issue.Severity.ERROR));

    private final String traceId;
    private final ClientCall call;
    private final GrpcStatusHandler statusConsumer;

    private final CompletableFuture> future = new CompletableFuture<>();
    private final AtomicReference value = new AtomicReference<>();

    public UnaryCall(String traceId, ClientCall call, GrpcStatusHandler statusConsumer) {
        this.traceId = traceId;
        this.call = call;
        this.statusConsumer = statusConsumer;
    }

    public CompletableFuture> startCall(ReqT request, Metadata headers) {
        try {
            call.start(this, headers);
            call.request(1);
            if (logger.isTraceEnabled()) {
                logger.trace("UnaryCall[{}] --> {}", traceId, TextFormat.shortDebugString((Message) request));
            }
            call.sendMessage(request);
            call.halfClose();
        } catch (Exception ex) {
            future.completeExceptionally(ex);
            try {
                call.cancel(ex.getMessage(), ex);
            } catch (Exception ex2) {
                logger.error("UnaryCall[{}] got exception while canceling", traceId, ex2);
            }
        }

        return future;
    }

    @Override
    public void onMessage(RespT value) {
        if (logger.isTraceEnabled()) {
            logger.trace("UnaryCall[{}] <-- {}", traceId, TextFormat.shortDebugString((Message) value));
        }
        if (!this.value.compareAndSet(null, value)) {
            future.complete(Result.fail(MULTIPLY_VALUES));
        }
    }

    @Override
    public void onClose(io.grpc.Status status, @Nullable Metadata trailers) {
        statusConsumer.accept(status, trailers);
        if (logger.isTraceEnabled()) {
            logger.trace("UnaryCall[{}] closed with status {}", traceId, status);
        }

        if (status.isOk()) {
            RespT snapshotValue = value.get();

            if (snapshotValue == null) {
                future.complete(Result.fail(NO_VALUE));
            } else {
                future.complete(Result.success(snapshotValue));
            }
        } else {
            future.complete(GrpcStatuses.toResult(status));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy