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

tech.ydb.topic.read.impl.ReaderImpl Maven / Gradle / Ivy

There is a newer version: 2.3.0
Show newest version
package tech.ydb.topic.read.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import tech.ydb.common.transaction.YdbTransaction;
import tech.ydb.core.Issue;
import tech.ydb.core.Status;
import tech.ydb.core.StatusCode;
import tech.ydb.core.grpc.GrpcRequestSettings;
import tech.ydb.core.utils.ProtobufUtils;
import tech.ydb.proto.StatusCodesProtos;
import tech.ydb.proto.topic.YdbTopic;
import tech.ydb.topic.TopicRpc;
import tech.ydb.topic.description.OffsetsRange;
import tech.ydb.topic.impl.GrpcStreamRetrier;
import tech.ydb.topic.read.PartitionOffsets;
import tech.ydb.topic.read.PartitionSession;
import tech.ydb.topic.read.events.DataReceivedEvent;
import tech.ydb.topic.settings.ReaderSettings;
import tech.ydb.topic.settings.StartPartitionSessionSettings;
import tech.ydb.topic.settings.TopicReadSettings;
import tech.ydb.topic.settings.UpdateOffsetsInTransactionSettings;

/**
 * @author Nikolay Perfilov
 */
public abstract class ReaderImpl extends GrpcStreamRetrier {
    private static final Logger logger = LoggerFactory.getLogger(ReaderImpl.class);

    private static final int DEFAULT_DECOMPRESSION_THREAD_COUNT = 4;

    private ReadSessionImpl session;
    private final ReaderSettings settings;
    private final TopicRpc topicRpc;
    private final Executor decompressionExecutor;
    private final ExecutorService defaultDecompressionExecutorService;
    private final AtomicReference> initResultFutureRef = new AtomicReference<>(null);

    // Every reading stream has a sequential number (for debug purposes)
    private final AtomicLong seqNumberCounter = new AtomicLong(0);

    public ReaderImpl(TopicRpc topicRpc, ReaderSettings settings) {
        super(topicRpc.getScheduler());
        this.topicRpc = topicRpc;
        this.settings = settings;
        this.session = new ReadSessionImpl();
        if (settings.getDecompressionExecutor() != null) {
            this.defaultDecompressionExecutorService = null;
            this.decompressionExecutor = settings.getDecompressionExecutor();
        } else {
            this.defaultDecompressionExecutorService = Executors.newFixedThreadPool(DEFAULT_DECOMPRESSION_THREAD_COUNT);
            this.decompressionExecutor = defaultDecompressionExecutorService;
        }
        StringBuilder message = new StringBuilder("Reader");
        if (settings.getReaderName() != null && !settings.getReaderName().isEmpty()) {
            message.append(" \"").append(settings.getReaderName()).append("\"");
        }
        message.append(" (generated id ").append(id).append(")");
        message.append(" created for topic(s): ");
        for (TopicReadSettings topic : settings.getTopics()) {
            if (topic != settings.getTopics().get(0)) {
                message.append(", ");
            }
            message.append("\"").append(topic.getPath()).append("\"");
        }
        if (settings.getConsumerName() != null) {
            message.append(" and Consumer: \"").append(settings.getConsumerName()).append("\"");
        } else {
            message.append(" without a Consumer");
        }
        logger.info(message.toString());
    }

    @Override
    protected Logger getLogger() {
        return logger;
    }

    @Override
    protected String getStreamName() {
        return "Reader";
    }

    protected CompletableFuture initImpl() {
        logger.info("[{}] initImpl called", id);
        if (initResultFutureRef.compareAndSet(null, new CompletableFuture<>())) {
            session.startAndInitialize();
        } else {
            logger.warn("[{}] Init is called on this reader more than once. Nothing is done", id);
        }
        return initResultFutureRef.get();
    }

    protected abstract CompletableFuture handleDataReceivedEvent(DataReceivedEvent event);
    protected abstract void handleCommitResponse(long committedOffset, PartitionSession partitionSession);
    protected abstract void handleStartPartitionSessionRequest(
            YdbTopic.StreamReadMessage.StartPartitionSessionRequest request,
            PartitionSession partitionSession,
            Consumer confirmCallback);
    protected abstract void handleStopPartitionSession(
            YdbTopic.StreamReadMessage.StopPartitionSessionRequest request,
            PartitionSession partitionSession,
            Runnable confirmCallback);
    protected abstract void handleClosePartitionSession(PartitionSession partitionSession);

    @Override
    protected void onStreamReconnect() {
        session = new ReadSessionImpl();
        session.startAndInitialize();
    }

    @Override
    protected void onShutdown(String reason) {
        session.shutdown();
        if (initResultFutureRef.get() != null && !initResultFutureRef.get().isDone()) {
            initResultFutureRef.get().completeExceptionally(new RuntimeException(reason));
        }
        if (defaultDecompressionExecutorService != null) {
            defaultDecompressionExecutorService.shutdown();
        }
    }

    protected CompletableFuture sendUpdateOffsetsInTransaction(YdbTransaction transaction,
                                                                       Map> offsets,
                                                                       UpdateOffsetsInTransactionSettings settings) {
        if (offsets.isEmpty()) {
            throw new IllegalArgumentException("Empty topic list to update in transaction");
        }
        if (logger.isDebugEnabled()) {
            StringBuilder str = new StringBuilder("Updating ");
            boolean first = true;
            for (Map.Entry> topicOffsets : offsets.entrySet()) {
                if (topicOffsets.getValue().isEmpty()) {
                    throw new IllegalArgumentException("Empty offsets range to update in transaction");
                }
                for (PartitionOffsets partitionOffsets : topicOffsets.getValue()) {
                    if (!first) {
                        str.append(", ");
                    } else {
                        first = false;
                    }
                    str.append("offsets [").append(partitionOffsets.getOffsets().get(0).getStart()).append("..")
                            .append(partitionOffsets.getOffsets().get(partitionOffsets.getOffsets().size() - 1)
                                    .getEnd()).append(") for partition ")
                            .append(partitionOffsets.getPartitionSession().getPartitionId())
                            .append(" [topic ").append(topicOffsets.getKey()).append("]");
                }
            }
            logger.debug(str.toString());
        }
        final ReadSessionImpl currentSession = session;
        transaction.getStatusFuture().whenComplete((status, error) -> {
            if (error != null) {
                currentSession.closeDueToError(null,
                        new RuntimeException("Restarting read session due to transaction " + transaction.getId() +
                                " with partition offsets from read session " + currentSession.fullId +
                                " was not committed with reason: " + error));
            } else if (!status.isSuccess()) {
                currentSession.closeDueToError(null,
                        new RuntimeException("Restarting read session due to transaction " + transaction.getId() +
                                " with partition offsets from read session " + currentSession.fullId +
                                " was not committed with status: " + status));
            }
        });
        YdbTopic.UpdateOffsetsInTransactionRequest.Builder requestBuilder = YdbTopic.UpdateOffsetsInTransactionRequest
                .newBuilder()
                .setTx(YdbTopic.TransactionIdentity.newBuilder()
                        .setId(transaction.getId())
                        .setSession(transaction.getSessionId()))
                .setConsumer(this.settings.getConsumerName());
        offsets.forEach((path, topicOffsets) -> {
            YdbTopic.UpdateOffsetsInTransactionRequest.TopicOffsets.Builder topicOffsetsBuilder = YdbTopic
                    .UpdateOffsetsInTransactionRequest.TopicOffsets.newBuilder()
                    .setPath(path);
            topicOffsets.forEach(partitionOffsets -> {
                YdbTopic.UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets.Builder partitionOffsetsBuilder
                        = YdbTopic.UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets.newBuilder()
                                .setPartitionId(partitionOffsets.getPartitionSession().getPartitionId());
                partitionOffsets.getOffsets().forEach(offsetsRange -> partitionOffsetsBuilder.addPartitionOffsets(
                        YdbTopic.OffsetsRange.newBuilder()
                                .setStart(offsetsRange.getStart())
                                .setEnd(offsetsRange.getEnd())
                                .build()));
                topicOffsetsBuilder.addPartitions(partitionOffsetsBuilder);
            });
            requestBuilder.addTopics(topicOffsetsBuilder);
        });

        String traceId = settings.getTraceId() == null ? UUID.randomUUID().toString() : settings.getTraceId();
        final GrpcRequestSettings grpcRequestSettings = GrpcRequestSettings.newBuilder()
                .withDeadline(settings.getRequestTimeout())
                .withTraceId(traceId)
                .build();
        return topicRpc.updateOffsetsInTransaction(requestBuilder.build(), grpcRequestSettings);
    }

    protected class ReadSessionImpl extends ReadSession {
        protected String sessionId = "";
        private final String fullId;
        // Total size to request with next ReadRequest.
        // Used to group several ReadResponses in one on high rps
        private final AtomicLong sizeBytesToRequest = new AtomicLong(0);
        private final Map partitionSessions = new ConcurrentHashMap<>();
        private ReadSessionImpl() {
            super(topicRpc);
            this.fullId = id + '.' + seqNumberCounter.incrementAndGet();
        }

        public void startAndInitialize() {
            logger.debug("[{}] Session {} startAndInitialize called", fullId, sessionId);
            start(this::processMessage).whenComplete(this::closeDueToError);

            YdbTopic.StreamReadMessage.InitRequest.Builder initRequestBuilder = YdbTopic.StreamReadMessage.InitRequest
                    .newBuilder();
            if (settings.getConsumerName() != null) {
                initRequestBuilder.setConsumer(settings.getConsumerName());
            }
            settings.getTopics().forEach(topicReadSettings -> {
                YdbTopic.StreamReadMessage.InitRequest.TopicReadSettings.Builder settingsBuilder =
                        YdbTopic.StreamReadMessage.InitRequest.TopicReadSettings.newBuilder()
                                .setPath(topicReadSettings.getPath());
                if (topicReadSettings.getPartitionIds() != null && !topicReadSettings.getPartitionIds().isEmpty()) {
                    settingsBuilder.addAllPartitionIds(topicReadSettings.getPartitionIds());
                }
                if (topicReadSettings.getMaxLag() != null) {
                    settingsBuilder.setMaxLag(ProtobufUtils.durationToProto(topicReadSettings.getMaxLag()));
                }
                if (topicReadSettings.getReadFrom() != null) {
                    settingsBuilder.setReadFrom(ProtobufUtils.instantToProto(topicReadSettings.getReadFrom()));
                }
                initRequestBuilder.addTopicsReadSettings(settingsBuilder);
            });

            if (settings.getReaderName() != null && !settings.getReaderName().isEmpty()) {
                initRequestBuilder.setReaderName(settings.getReaderName());
            }

            send(YdbTopic.StreamReadMessage.FromClient.newBuilder()
                    .setInitRequest(initRequestBuilder)
                    .build());
        }

        private void sendReadRequest() {
            long currentSizeBytesToRequest = sizeBytesToRequest.getAndSet(0);
            if (currentSizeBytesToRequest <= 0) {
                logger.debug("[{}] Nothing to request in DataRequest. sizeBytesToRequest == {}", fullId,
                        currentSizeBytesToRequest);
                return;
            }
            logger.debug("[{}] Sending DataRequest with {} bytes", fullId, currentSizeBytesToRequest);

            send(YdbTopic.StreamReadMessage.FromClient.newBuilder()
                    .setReadRequest(YdbTopic.StreamReadMessage.ReadRequest.newBuilder()
                            .setBytesSize(currentSizeBytesToRequest)
                            .build())
                    .build());
        }

        private void sendStartPartitionSessionResponse(PartitionSessionImpl partitionSession,
                                                         StartPartitionSessionSettings startSettings) {
            if (!isWorking.get()) {
                logger.info("[{}] Need to send StartPartitionSessionResponse for partition session {} (partition {})," +
                        " but reading session is already closed", fullId, partitionSession.getId(),
                        partitionSession.getPartitionId());
                return;
            }
            if (!partitionSessions.containsKey(partitionSession.getId())) {
                logger.info("[{}] Need to send StartPartitionSessionResponse for partition session {} (partition {})," +
                                " but have no such partition session active", fullId, partitionSession.getId(),
                        partitionSession.getPartitionId());
                return;
            }
            YdbTopic.StreamReadMessage.StartPartitionSessionResponse.Builder responseBuilder =
                    YdbTopic.StreamReadMessage.StartPartitionSessionResponse.newBuilder()
                            .setPartitionSessionId(partitionSession.getId());
            Long userDefinedReadOffset = null;
            Long userDefinedCommitOffset = null;
            if (startSettings != null) {
                userDefinedReadOffset = startSettings.getReadOffset();
                if (userDefinedReadOffset != null) {
                    responseBuilder.setReadOffset(userDefinedReadOffset);
                    partitionSession.setLastReadOffset(userDefinedReadOffset);
                }
                userDefinedCommitOffset = startSettings.getCommitOffset();
                if (userDefinedCommitOffset != null) {
                    responseBuilder.setCommitOffset(userDefinedCommitOffset);
                    partitionSession.setLastCommittedOffset(userDefinedCommitOffset);
                }
            }
            logger.info("[{}] Sending StartPartitionSessionResponse for partition session {} (partition {})" +
                            " with readOffset {} and commitOffset {}", fullId, partitionSession.getId(),
                    partitionSession.getPartitionId(), userDefinedReadOffset, userDefinedCommitOffset);
            send(YdbTopic.StreamReadMessage.FromClient.newBuilder()
                    .setStartPartitionSessionResponse(responseBuilder.build())
                    .build());
        }

        private void sendStopPartitionSessionResponse(long partitionSessionId) {
            if (!isWorking.get()) {
                logger.info("[{}] Need to send StopPartitionSessionResponse for partition session {}, " +
                        "but reading session is already closed", fullId, partitionSessionId);
                return;
            }
            PartitionSessionImpl partitionSession = partitionSessions.remove(partitionSessionId);
            if (partitionSession != null) {
                partitionSession.shutdown();
                logger.info("[{}] Sending StopPartitionSessionResponse for partition session {} (partition {})", fullId,
                        partitionSessionId, partitionSession.getPartitionId());
            } else {
                logger.warn("[{}] Sending StopPartitionSessionResponse for partition session {}, " +
                        "but have no such partition session active", fullId, partitionSessionId);
            }
            send(YdbTopic.StreamReadMessage.FromClient.newBuilder()
                    .setStopPartitionSessionResponse(
                            YdbTopic.StreamReadMessage.StopPartitionSessionResponse.newBuilder()
                                    .setPartitionSessionId(partitionSessionId)
                                    .build())
                    .build());
        }

        private void sendCommitOffsetRequest(long partitionSessionId, long partitionId,
                                       List rangesToCommit) {
            if (!isWorking.get()) {
                if (logger.isInfoEnabled()) {
                    StringBuilder message = new StringBuilder("[").append(fullId)
                            .append("] Need to send CommitRequest for partition session ").append(partitionSessionId)
                            .append(" (partition ").append(partitionId).append(") with offset ranges ");
                    for (int i = 0; i < rangesToCommit.size(); i++) {
                        if (i > 0) {
                            message.append(", ");
                        }
                        OffsetsRange range = rangesToCommit.get(i);
                        message.append("[").append(range.getStart()).append(",").append(range.getEnd()).append(")");
                    }
                    message.append(", but reading session is already closed");
                    logger.info(message.toString());
                }
                return;
            }

            YdbTopic.StreamReadMessage.CommitOffsetRequest.PartitionCommitOffset.Builder builder =
            YdbTopic.StreamReadMessage.CommitOffsetRequest.PartitionCommitOffset.newBuilder()
                    .setPartitionSessionId(partitionSessionId);
            rangesToCommit.forEach(range -> {
                builder.addOffsets(YdbTopic.OffsetsRange.newBuilder()
                        .setStart(range.getStart())
                        .setEnd(range.getEnd()));
            });
            send(YdbTopic.StreamReadMessage.FromClient.newBuilder()
                    .setCommitOffsetRequest(YdbTopic.StreamReadMessage.CommitOffsetRequest.newBuilder()
                            .addCommitOffsets(builder))
                    .build());

        }

        private void closePartitionSessions() {
            partitionSessions.values().forEach(this::closePartitionSession);
            partitionSessions.clear();
        }

        private void closePartitionSession(PartitionSessionImpl partitionSession) {
            partitionSession.shutdown();
            handleClosePartitionSession(partitionSession.getSessionInfo());
        }

        private void onInitResponse(YdbTopic.StreamReadMessage.InitResponse response) {
            sessionId = response.getSessionId();

            if (initResultFutureRef.get() != null) {
                initResultFutureRef.get().complete(null);
            }
            sizeBytesToRequest.set(settings.getMaxMemoryUsageBytes());
            logger.info("[{}] Session {} initialized. Requesting {} bytes...", fullId, sessionId,
                    settings.getMaxMemoryUsageBytes());
            sendReadRequest();
        }

        private void onStartPartitionSessionRequest(YdbTopic.StreamReadMessage.StartPartitionSessionRequest request) {
            long partitionSessionId = request.getPartitionSession().getPartitionSessionId();
            long partitionId = request.getPartitionSession().getPartitionId();
            logger.info("[{}] Received StartPartitionSessionRequest: partition session {} (partition {}) " +
                            "with committedOffset {} and partitionOffsets [{}-{})", fullId,
                    partitionSessionId, partitionId, request.getCommittedOffset(),
                    request.getPartitionOffsets().getStart(), request.getPartitionOffsets().getEnd());

            PartitionSessionImpl partitionSession = PartitionSessionImpl.newBuilder()
                    .setId(partitionSessionId)
                    .setPath(request.getPartitionSession().getPath())
                    .setPartitionId(partitionId)
                    .setCommittedOffset(request.getCommittedOffset())
                    .setPartitionOffsets(new OffsetsRangeImpl(request.getPartitionOffsets().getStart(),
                            request.getPartitionOffsets().getEnd()))
                    .setDecompressionExecutor(decompressionExecutor)
                    .setDataEventCallback(ReaderImpl.this::handleDataReceivedEvent)
                    .setCommitFunction((offsets) -> sendCommitOffsetRequest(partitionSessionId, partitionId, offsets))
                    .build();
            partitionSessions.put(partitionSession.getId(), partitionSession);

            handleStartPartitionSessionRequest(request, partitionSession.getSessionInfo(),
                    (settings) -> sendStartPartitionSessionResponse(partitionSession, settings));
        }

        protected void onStopPartitionSessionRequest(YdbTopic.StreamReadMessage.StopPartitionSessionRequest request) {
            if (request.getGraceful()) {
                PartitionSessionImpl partitionSession = partitionSessions.get(request.getPartitionSessionId());
                if (partitionSession != null) {
                    logger.info("[{}] Received graceful StopPartitionSessionRequest for partition session {} " +
                            "(partition {})", fullId, partitionSession.getId(), partitionSession.getPartitionId());
                    handleStopPartitionSession(request, partitionSession.getSessionInfo(),
                            () -> sendStopPartitionSessionResponse(request.getPartitionSessionId()));
                } else {
                    logger.error("[{}] Received graceful StopPartitionSessionRequest for partition session {}, " +
                            "but have no such partition session active", fullId, request.getPartitionSessionId());
                    closeDueToError(null,
                            new RuntimeException("Restarting read session due to receiving " +
                                    "StopPartitionSessionRequest with PartitionSessionId " +
                                    request.getPartitionSessionId() + " that SDK knows nothing about"));
                }
            } else {
                PartitionSessionImpl partitionSession = partitionSessions.remove(request.getPartitionSessionId());
                if (partitionSession != null) {
                    logger.info("[{}] Received force StopPartitionSessionRequest for partition session {} (partition " +
                                    "{})", fullId, partitionSession.getId(), partitionSession.getPartitionId());
                    closePartitionSession(partitionSession);
                } else {
                    logger.info("[{}] Received force StopPartitionSessionRequest for partition session {}, " +
                            "but have no such partition session running", fullId, request.getPartitionSessionId());
                }
            }
        }

        private void onReadResponse(YdbTopic.StreamReadMessage.ReadResponse readResponse) {
            final long responseBytesSize = readResponse.getBytesSize();
            logger.trace("[{}] Received ReadResponse of {} bytes", fullId, responseBytesSize);
            List> batchReadFutures = new ArrayList<>();
            readResponse.getPartitionDataList().forEach(
                    (YdbTopic.StreamReadMessage.ReadResponse.PartitionData data) -> {
                        long partitionId = data.getPartitionSessionId();
                        PartitionSessionImpl partitionSession = partitionSessions.get(partitionId);
                        if (partitionSession != null) {
                            // Completes when all messages from a batch are read by user
                            CompletableFuture readFuture = partitionSession.addBatches(data.getBatchesList());
                            batchReadFutures.add(readFuture);
                        } else {
                            logger.error("[{}] Received PartitionData for unknown(closed?) PartitionSessionId={}. " +
                                            "This shouldn't happen",
                                    fullId, partitionId);
                        }
                    });
            CompletableFuture.allOf(batchReadFutures.toArray(new CompletableFuture[0]))
                    .whenComplete((res, th) -> {
                        if (th != null) {
                            logger.error("[{}] Exception while waiting for batches to be read:", fullId, th);
                        }
                        if (isWorking.get()) {
                            logger.trace("[{}] Finished handling ReadResponse of {} bytes. Sending ReadRequest...",
                                    fullId, responseBytesSize);
                            this.sizeBytesToRequest.addAndGet(responseBytesSize);
                            sendReadRequest();
                        } else {
                            logger.trace("[{}] Finished handling ReadResponse of {} bytes. Read session is already " +
                                    "closed -- no need to send ReadRequest", fullId, responseBytesSize);
                        }
                    });
        }

        protected void onCommitOffsetResponse(YdbTopic.StreamReadMessage.CommitOffsetResponse response) {
            logger.trace("[{}] Received CommitOffsetResponse", fullId);
            for (YdbTopic.StreamReadMessage.CommitOffsetResponse.PartitionCommittedOffset partitionCommittedOffset :
                    response.getPartitionsCommittedOffsetsList()) {
                PartitionSessionImpl partitionSession =
                        partitionSessions.get(partitionCommittedOffset.getPartitionSessionId());
                if (partitionSession != null) {
                    // Handling CompletableFuture completions for single commits
                    partitionSession.handleCommitResponse(partitionCommittedOffset.getCommittedOffset());
                    // Handling onCommitResponse callback
                    handleCommitResponse(partitionCommittedOffset.getCommittedOffset(),
                            partitionSession.getSessionInfo());
                } else {
                    logger.error("[{}] Received CommitOffsetResponse for unknown (closed?) partition session with " +
                                    "id={}. This shouldn't happen", fullId,
                            partitionCommittedOffset.getPartitionSessionId());
                }
            }
        }

        protected void onPartitionSessionStatusResponse(
                YdbTopic.StreamReadMessage.PartitionSessionStatusResponse response) {
            PartitionSessionImpl partitionSession = partitionSessions.get(response.getPartitionSessionId());
            logger.info("[{}] Received PartitionSessionStatusResponse: partition session {} (partition {})." +
                            " Partition offsets: [{}, {}). Committed offset: {}", fullId,
                    response.getPartitionSessionId(),
                    partitionSession == null ? "unknown" : partitionSession.getPartitionId(),
                    response.getPartitionOffsets().getStart(), response.getPartitionOffsets().getEnd(),
                    response.getCommittedOffset());
        }

        private void processMessage(YdbTopic.StreamReadMessage.FromServer message) {
            if (!isWorking.get()) {
                logger.debug("[{}] processMessage called, but read session is already closed", fullId);
                return;
            }
            logger.debug("[{}] processMessage called", fullId);
            if (message.getStatus() == StatusCodesProtos.StatusIds.StatusCode.SUCCESS) {
                reconnectCounter.set(0);
            } else {
                Status status = Status.of(StatusCode.fromProto(message.getStatus()),
                        Issue.fromPb(message.getIssuesList()));
                logger.warn("[{}] Got non-success status in processMessage method: {}", fullId, status);
                closeDueToError(status, null);
                return;
            }

            if (message.hasInitResponse()) {
                onInitResponse(message.getInitResponse());
            } else if (message.hasStartPartitionSessionRequest()) {
                onStartPartitionSessionRequest(message.getStartPartitionSessionRequest());
            } else if (message.hasStopPartitionSessionRequest()) {
                onStopPartitionSessionRequest(message.getStopPartitionSessionRequest());
            } else if (message.hasReadResponse()) {
                onReadResponse(message.getReadResponse());
            } else if (message.hasCommitOffsetResponse()) {
                onCommitOffsetResponse(message.getCommitOffsetResponse());
            } else if (message.hasPartitionSessionStatusResponse()) {
                onPartitionSessionStatusResponse(message.getPartitionSessionStatusResponse());
            } else if (message.hasUpdateTokenResponse()) {
                logger.debug("[{}] Received UpdateTokenResponse", fullId);
            } else {
                logger.error("[{}] Unhandled message from server: {}", fullId, message);
            }
        }

        protected void closeDueToError(Status status, Throwable th) {
            logger.info("[{}] Session {} closeDueToError called", fullId, sessionId);
            if (shutdown()) {
                // Signal reader to retry
                onSessionClosed(status, th);
            }
        }

        @Override
        protected void onStop() {
            logger.debug("[{}] Session {} onStop called", fullId, sessionId);
            closePartitionSessions();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy