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

com.xiaomi.infra.galaxy.talos.consumer.TalosMessageReader Maven / Gradle / Ivy

There is a newer version: 2.6.1.4
Show newest version
/**
 * Copyright 2015, Xiaomi.
 * All rights reserved.
 * Author: [email protected]
 */

package com.xiaomi.infra.galaxy.talos.consumer;

import java.util.List;

import libthrift091.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xiaomi.infra.galaxy.talos.thrift.CheckPoint;
import com.xiaomi.infra.galaxy.talos.thrift.MessageAndOffset;
import com.xiaomi.infra.galaxy.talos.thrift.QueryOffsetRequest;
import com.xiaomi.infra.galaxy.talos.thrift.QueryOffsetResponse;
import com.xiaomi.infra.galaxy.talos.thrift.UpdateOffsetRequest;
import com.xiaomi.infra.galaxy.talos.thrift.UpdateOffsetResponse;

public class TalosMessageReader extends MessageReader implements MessageCheckpointer {
  private static final Logger LOG = LoggerFactory.getLogger(TalosMessageReader.class);

  public TalosMessageReader(TalosConsumerConfig talosConsumerConfig) {
    super(talosConsumerConfig);
  }

  @Override
  public void initStartOffset() throws Exception {
    // get last commit offset
    long readingStartOffset = queryStartOffset();

    // when consumer starting up, checking:
    // 1) whether not exist last commit offset, which means 'readingStartOffset==-1'
    // 2) whether reset offset
    if (readingStartOffset == -1 || consumerConfig.isResetOffsetWhenStart()) {
      startOffset.set(consumerConfig.getResetOffsetValueWhenStart());
    } else {
      startOffset.set(readingStartOffset);
    }

    // guarantee lastCommitOffset and finishedOffset correct
    if (startOffset.longValue() > 0) {
      lastCommitOffset = finishedOffset = startOffset.get() - 1;
    }
    LOG.info("Init startOffset: " + startOffset + " lastCommitOffset: " +
        lastCommitOffset + " for partition: " + topicAndPartition);
    messageProcessor.init(topicAndPartition, startOffset.get());
  }

  @Override
  public void commitCheckPoint() throws Exception {
    innerCheckpoint();
    messageProcessor.shutdown(this);
  }

  @Override
  public void fetchData() {
    // control fetch qps
    if (System.currentTimeMillis() - lastFetchTime < fetchInterval) {
      try {
        Thread.sleep(lastFetchTime + fetchInterval - System.currentTimeMillis());
      } catch (InterruptedException e) {
        // do nothing
      }
    }

    // fetch data and process them
    try {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Reading message from offset: " + startOffset.get() +
            " of partition: " + topicAndPartition.getPartitionId());
      }
      List messageList = simpleConsumer.fetchMessage(
          startOffset.get());
      lastFetchTime = System.currentTimeMillis();
      // return when no message got
      if (messageList == null || messageList.size() == 0) {
        return;
      }

      /**
       * Note: We guarantee the committed offset must be the messages that
       * have been processed by user's MessageProcessor;
       */
      finishedOffset = messageList.get(messageList.size() - 1).getMessageOffset();
      messageProcessor.process(messageList, this);
      startOffset.set(finishedOffset + 1);
      if (shoudCommit()) {
        try {
          innerCheckpoint();
        } catch (TException e) {
          // when commitOffset failed, we just do nothing;
          LOG.error("commit offset error: " + e.toString() + " skip to it");
        }
      }
    } catch (Throwable e) {
      LOG.error("Error: " + e.toString() + " when getting messages from topic: " +
          topicAndPartition.getTopicTalosResourceName() + " partition: " +
          topicAndPartition.getPartitionId());

      processFetchException(e);
      lastFetchTime = System.currentTimeMillis();
    } // catch
  } // fetchData

  private long queryStartOffset() throws TException {
    QueryOffsetRequest queryOffsetRequest = new QueryOffsetRequest(
        consumerGroup, topicAndPartition);
    QueryOffsetResponse queryOffsetResponse = consumerClient.queryOffset(
        queryOffsetRequest);

    long committedOffset = queryOffsetResponse.getMsgOffset();
    // 'committedOffset == -1' means not exist last committed offset
    // startOffset = committedOffset + 1
    return ((committedOffset == -1) ? -1 : committedOffset + 1);
  }

  private void innerCheckpoint() throws TException {
    if (consumerConfig.isCheckpointAutoCommit()) {
      commitOffset(finishedOffset);
    }
  }

  @Override
  public boolean checkpoint() {
    return checkpoint(finishedOffset);
  }

  @Override
  public boolean checkpoint(long messageOffset) {
    LOG.info("start checkpoint: " + messageOffset);
    if (consumerConfig.isCheckpointAutoCommit()) {
      LOG.info("You can not checkpoint through MessageCheckpointer when you set " +
          "\"galaxy.talos.consumer.checkpoint.message.offset\" as \"true\"");
      return false;
    }

    if (messageOffset <= lastCommitOffset || messageOffset > finishedOffset) {
      LOG.info("checkpoint messageOffset: " + messageOffset + " in wrong " +
          "range, lastCheckpoint messageOffset: " + lastCommitOffset + ", last " +
          "deliver messageOffset: " + finishedOffset);
      return false;
    }

    try {
      commitOffset(messageOffset);
      return true;
    } catch (TException e) {
      return false;
    }
  }

  private void commitOffset(long messageOffset) throws TException {
    CheckPoint checkPoint = new CheckPoint(consumerGroup, topicAndPartition,
        messageOffset, workerId);
    // check whether to check last commit offset, firstCommit do not check
    if ((lastCommitOffset != -1) && consumerConfig.isCheckLastCommitOffset()) {
      checkPoint.setLastCommitOffset(lastCommitOffset);
    }

    UpdateOffsetRequest updateOffsetRequest = new UpdateOffsetRequest(checkPoint);
    UpdateOffsetResponse updateOffsetResponse = consumerClient.updateOffset(
        updateOffsetRequest);
    // update startOffset as next message
    if (updateOffsetResponse.isSuccess()) {
      lastCommitOffset = messageOffset;
      lastCommitTime = System.currentTimeMillis();
      LOG.info("Worker: " + workerId + " commit offset: " +
          lastCommitOffset + " for partition: " +
          topicAndPartition.getPartitionId());
    } else {
      LOG.error("Worker: " + workerId + " commit offset: " +
          lastCommitOffset + " for partition: " +
          topicAndPartition.getPartitionId() + " failed");
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy