com.xiaomi.infra.galaxy.talos.producer.PartitionSender Maven / Gradle / Ivy
/**
* Copyright 2015, Xiaomi.
* All rights reserved.
* Author: [email protected]
*/
package com.xiaomi.infra.galaxy.talos.producer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.xiaomi.infra.galaxy.talos.client.Utils;
import com.xiaomi.infra.galaxy.talos.thrift.Message;
import com.xiaomi.infra.galaxy.talos.thrift.MessageService;
import com.xiaomi.infra.galaxy.talos.thrift.TopicAndPartition;
import com.xiaomi.infra.galaxy.talos.thrift.TopicTalosResourceName;
public class PartitionSender {
private class MessageCallbackTask implements Runnable {
private UserMessageResult userMessageResult;
private MessageCallbackTask(UserMessageResult userMessageResult) {
this.userMessageResult = userMessageResult;
}
@Override
public void run() {
if (userMessageResult.isSuccessful()) {
userMessageCallback.onSuccess(userMessageResult);
} else {
userMessageCallback.onError(userMessageResult);
}
}
} // MessageCallbackTask
private class MessageWriter implements Runnable {
private SimpleProducer simpleProducer;
private MessageWriter() {
simpleProducer = new SimpleProducer(talosProducerConfig,
topicAndPartition, messageClient, clientId, requestId);
}
@Override
public void run() {
while (true) {
try {
List messageList =
partitionMessageQueue.getMessageList();
// when messageList return no message, this means TalosProducer not
// alive and there is no more message to send , then we should exit
// write message right now;
if (messageList.isEmpty()) {
// notify to wake up producer's global lock
synchronized (globalLock) {
globalLock.notifyAll();
}
break;
}
putMessage(messageList);
} catch (Throwable throwable) {
LOG.error("PutMessageTask for topicAndPartition: " +
topicAndPartition + " failed", throwable);
} finally {
// notify to wake up producer's global lock
synchronized (globalLock) {
globalLock.notifyAll();
}
}
} // while
} // run
private void putMessage(List messageList) {
UserMessageResult userMessageResult = new UserMessageResult(
messageList, partitionId);
try {
// when TalosProducer is disabled, we just fail the message and inform user;
// but when TalosProducer is shutdown, we will send the left message.
if (producer.isDisabled()) {
throw new Throwable("The Topic: " + topicAndPartition.getTopicName() +
" with resourceName: " + topicAndPartition.getTopicTalosResourceName() +
" no longer exist. Please check the topic and reconstruct the" +
" TalosProducer again");
}
simpleProducer.doPut(messageList);
// putMessage success callback
userMessageResult.setSuccessful(true);
messageCallbackExecutors.execute(
new MessageCallbackTask(userMessageResult));
if (LOG.isDebugEnabled()) {
LOG.debug("put " + messageList.size() +
" message success for partition: " + partitionId);
}
} catch (Throwable e) {
LOG.error("Failed to put " + messageList.size() +
" messages for partition: " + partitionId, e);
if (LOG.isDebugEnabled()) {
for (Message message : messageList) {
LOG.error(message.getSequenceNumber() + ": " +
new String(message.getMessage()));
}
}
// putMessage failed callback
userMessageResult.setSuccessful(false).setCause(e);
messageCallbackExecutors.execute(
new MessageCallbackTask(userMessageResult));
// delay when partitionNotServing
if (Utils.isPartitionNotServing(e)) {
LOG.warn("Partition: " + partitionId +
" is not serving state, sleep a while for waiting it work.");
try {
Thread.sleep(talosProducerConfig.getWaitPartitionWorkingTime());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
} // if
} // catch
}
} // MessageWriter
private static final Logger LOG = LoggerFactory.getLogger(PartitionSender.class);
private int partitionId;
// a static attribute of TalosProducer which will guarantee that
// the requestId of all PartitionSender always be global unique
private AtomicLong requestId;
private String clientId;
private TalosProducerConfig talosProducerConfig;
private MessageService.Iface messageClient;
private UserMessageCallback userMessageCallback;
private TopicAndPartition topicAndPartition;
private PartitionMessageQueue partitionMessageQueue;
private ScheduledExecutorService singleExecutor;
private Future messageWriterFuture;
private ExecutorService messageCallbackExecutors;
private final Object globalLock;
private TalosProducer producer;
public PartitionSender(int partitionId, String topicName,
TopicTalosResourceName topicTalosResourceName, AtomicLong requestId,
String clientId, TalosProducerConfig talosProducerConfig,
MessageService.Iface messageClient, UserMessageCallback userMessageCallback,
ExecutorService messageCallbackExecutors,
Object globalLock, TalosProducer producer) {
this.partitionId = partitionId;
this.requestId = requestId;
this.clientId = clientId;
this.talosProducerConfig = talosProducerConfig;
this.messageClient = messageClient;
this.userMessageCallback = userMessageCallback;
this.messageCallbackExecutors = messageCallbackExecutors;
this.globalLock = globalLock;
this.producer = producer;
topicAndPartition = new TopicAndPartition(topicName,
topicTalosResourceName, partitionId);
partitionMessageQueue = new PartitionMessageQueue(talosProducerConfig,
partitionId, producer);
singleExecutor = Executors.newSingleThreadScheduledExecutor();
messageWriterFuture = singleExecutor.submit(new MessageWriter());
}
public void shutdown() {
// notify PartitionMessageQueue::getMessageList return;
addMessage(new ArrayList());
singleExecutor.shutdown();
while (true) {
try {
if (singleExecutor.awaitTermination(100, TimeUnit.MILLISECONDS)) {
break;
}
} catch (InterruptedException e) {
}
}
LOG.info("PartitionSender for partition: " + partitionId + " finish stop");
}
public void addMessage(List userMessageList) {
partitionMessageQueue.addMessage(userMessageList);
if (LOG.isDebugEnabled()) {
LOG.debug("add " + userMessageList.size() +
" messages to partition: " + partitionId);
}
}
}