blob: 1a8bfed9f3d446df1f22868ab941c81a106cdf27 [file]
/**
* Copyright (C) 2013 suwenkuang ,hooligan_520@qq.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Common.h"
#include "DefaultMQPushConsumer.h"
using namespace rmq;
volatile long long g_lastCnt = 0;
volatile long long g_totalCnt = 0;
long long g_lastUpdateTime = 0;
static std::string bin2str(const std::string& strBin)
{
if(strBin.size() == 0)
{
return "";
}
std::string sOut;
const char *p = (const char *)strBin.data();
size_t len = strBin.size();
char sBuf[255];
for (size_t i = 0; i < len; ++i, ++p)
{
snprintf(sBuf, sizeof(sBuf), "%02x", (unsigned char) *p);
sOut += sBuf;
}
return sOut;
}
class MsgListener : public MessageListenerConcurrently
{
public:
MsgListener()
{
consumeTimes = 0;
}
~MsgListener()
{
}
/**
* consume messages
* !!!Notice:multi-thread call, need to pay attention to dealing with multi-threaded re-entry problem
* @param msgs message list
* @param context context for consumer
* @return [CONSUME_SUCCESS- success,RECONSUME_LATER-consume fail and retry later]
*/
ConsumeConcurrentlyStatus consumeMessage(std::list<MessageExt*>& msgs,
ConsumeConcurrentlyContext& context)
{
int cnt = __sync_fetch_and_add(&g_totalCnt, 1);
long long now = MyUtil::getNowMs();
long long old = g_lastUpdateTime;
if ((now - old) >= 1000)
{
if (__sync_bool_compare_and_swap(&g_lastUpdateTime, old, now))
{
long long time = now - old;
int tps = (int)((g_totalCnt - g_lastCnt) * 1.0 / time * 1000.0);
g_lastCnt = g_totalCnt;
MYDEBUG("[consume]msgcount: %lld, TPS: %d\n", g_totalCnt, tps);
}
}
MessageExt* msg = msgs.front();
long long offset = msg->getQueueOffset();
std::string maxOffset = msg->getProperty(Message::PROPERTY_MAX_OFFSET);
long long diff = MyUtil::str2ll(maxOffset.c_str()) - offset;
if (diff > 100000)
{
if (diff % 10000 == 0)
{
MYDEBUG("overload, offset:%lld, diff:%lld\n", offset, diff);
}
// return CONSUME_SUCCESS;
}
std::list<MessageExt*>::iterator it = msgs.begin();
for (;it != msgs.end();it++)
{
MessageExt* me = *it;
std::string str;
str.assign(me->getBody(),me->getBodyLen());
MYLOG("[%d]|%s|%s\n", cnt, me->toString().c_str(), str.c_str());
}
consumeTimes++;
/*
if ((consumeTimes % 2) == 0)
{
return RECONSUME_LATER;
}
else if ((consumeTimes % 3) == 0)
{
context.delayLevelWhenNextConsume = 5;
return RECONSUME_LATER;
}
*/
// context.ackIndex = msgs.size() - 1;
return CONSUME_SUCCESS;
}
int consumeTimes;
};
void Usage(const char* program)
{
printf("Usage:%s ip:port [-g group] [-t topic] [-w logpath]\n", program);
printf("\t -g consumer group\n");
printf("\t -t topic\n");
printf("\t -w log path\n");
}
int main(int argc, char* argv[])
{
if (argc < 2)
{
Usage(argv[0]);
return 0;
}
std::string namesrv = argv[1];
std::string group = "cg_test_push_group";
std::string topic = "topic_test";
for (int i=2; i< argc; i++)
{
if (strcmp(argv[i],"-g")==0)
{
if (i+1 < argc)
{
group = argv[i+1];
i++;
}
else
{
Usage(argv[0]);
return 0;
}
}
else if (strcmp(argv[i],"-t")==0)
{
if (i+1 < argc)
{
topic = argv[i+1];
i++;
}
else
{
Usage(argv[0]);
return 0;
}
}
else if (strcmp(argv[i],"-w")==0)
{
if (i+1 < argc)
{
MyUtil::initLog(argv[i+1]);
i++;
}
else
{
Usage(argv[0]);
return 0;
}
}
else
{
Usage(argv[0]);
return 0;
}
}
// init client api log, here is not necessary, need to debug the api need to be initialized, you can consider comment it
// Here only the default print warning, error log, the log will be rolling by day, if you need to modify the log level, please set the environment variable, export ROCKETMQ_LOGLEVEL = loglevel
// The log level is as follows:
// 0 - close the log
// 1 - write error log
// 2 - write error, warning log
// 3 - write error, warning, info log
// 4 - write errors, warnings, info, debug logs
RocketMQUtil::initLog("/tmp/rocketmq_pushconsumer.log");
RMQ_DEBUG("consumer.new: %s", group.c_str());
DefaultMQPushConsumer consumer(group);
RMQ_DEBUG("consumer.setNamesrvAddr: %s", namesrv.c_str());
consumer.setNamesrvAddr(namesrv);
RMQ_DEBUG("consumer.setMessageModel: %s", getMessageModelString(CLUSTERING));
consumer.setMessageModel(CLUSTERING);
RMQ_DEBUG("consumer.subscribe");
consumer.subscribe(topic, "*");
consumer.setConsumeFromWhere(CONSUME_FROM_LAST_OFFSET);
// Set the number of each consumption message, the default is 1
// consumer.setConsumeMessageBatchMaxSize(1);
// The number of consumer thread pool, the default minimum 5, the maximum 25, the proposed set to the same, more stable
// consumer.setConsumeThreadMin(25);
// consumer.setConsumeThreadMax(25);
// Single message consume timeout, default is 15 minutes
// When the consumption times out, message will be send back to the retry queue and re-delivered
// consumer.setConsumeTimeout(15);
RMQ_DEBUG("consumer.registerMessageListener");
MsgListener* listener = new MsgListener();
consumer.registerMessageListener(listener);
RMQ_DEBUG("consumer.start");
consumer.start();
while(1)
{
if (getchar()=='e'&&getchar()=='x'&&getchar()=='i'&&getchar()=='t')
{
break;
}
::sleep(1);
}
RMQ_DEBUG("consumer.shutdown");
consumer.shutdown();
delete listener;
return 0;
}