rabbitmq method之basic.consume
basic.consume指的是channel在 某个队列上注册消费者,那在这个队列有消息来了之后,就会把消息转发到给此channel处理,如果 这个队列有多个消费者,则会采用轮转的方式将消息分发给消息者.
首先是rabbit_reader接收数据包后,解析组装出其中的method,channel方法交给channel处理.具体过程见http://www.cnblogs.com/haoqingchuan/p/4354692.html
channel进程处理basic.consume的方法.先从状态中查看是否已经存在此tag(以channel为域,不同的consumer_tag标识了不同的消费者,每个channel的内的consumer tag必须是唯一的).如果没有查找到则正常,如果未对队列名字命名,则会产生一个uuid来作为队列名.
handle_method(#'basic.consume'{queue = QueueNameBin,
consumer_tag = ConsumerTag,
no_local = _, % FIXME: implement
no_ack = NoAck,
exclusive = ExclusiveConsume,
nowait = NoWait,
arguments = Args},
_, State = #ch{consumer_prefetch = ConsumerPrefetch,
consumer_mapping = ConsumerMapping}) ->
case dict:find(ConsumerTag, ConsumerMapping) of
error ->
QueueName = qbin_to_resource(QueueNameBin, State),
check_read_permitted(QueueName, State),
ActualConsumerTag =
case ConsumerTag of
<<>> -> rabbit_guid:binary(rabbit_guid:gen_secure(),
"amq.ctag");
Other -> Other
end,
case basic_consume(
QueueName, NoAck, ConsumerPrefetch, ActualConsumerTag,
ExclusiveConsume, Args, NoWait, State) of
{ok, State1} ->
{noreply, State1};
{error, exclusive_consume_unavailable} ->
rabbit_misc:protocol_error(
access_refused, "~s in exclusive use",
[rabbit_misc:rs(QueueName)])
end;
{ok, _} ->
%% Attempted reuse of consumer tag.
rabbit_misc:protocol_error(
not_allowed, "attempt to reuse consumer tag '~s'", [ConsumerTag])
end;
basic_consume(QueueName, NoAck, ConsumerPrefetch, ActualConsumerTag,
ExclusiveConsume, Args, NoWait,
State = #ch{conn_pid = ConnPid,
limiter = Limiter,
consumer_mapping = ConsumerMapping}) ->
case rabbit_amqqueue:with_exclusive_access_or_die(
QueueName, ConnPid,
fun (Q) ->
{rabbit_amqqueue:basic_consume(
Q, NoAck, self(),
rabbit_limiter:pid(Limiter),
rabbit_limiter:is_active(Limiter),
ConsumerPrefetch, ActualConsumerTag,
ExclusiveConsume, Args,
ok_msg(NoWait, #'basic.consume_ok'{
consumer_tag = ActualConsumerTag})),
Q}
end) of
{ok, Q = #amqqueue{pid = QPid, name = QName}} ->
CM1 = dict:store(
ActualConsumerTag,
{Q, {NoAck, ConsumerPrefetch, ExclusiveConsume, Args}},
ConsumerMapping),
State1 = monitor_delivering_queue(
NoAck, QPid, QName,
State#ch{consumer_mapping = CM1}),
{ok, case NoWait of
true -> consumer_monitor(ActualConsumerTag, State1);
false -> State1
end};
{{error, exclusive_consume_unavailable} = E, _Q} ->
E
end.
rabbit_amqqueue.erl
rabbitmq_channel进程向rabbitmq_amqp_process进程发送消息来完成增加消费者的动作
basic_consume(#amqqueue{pid = QPid, name = QName}, NoAck, ChPid, LimiterPid,
LimiterActive, ConsumerPrefetchCount, ConsumerTag,
ExclusiveConsume, Args, OkMsg) ->
ok = check_consume_arguments(QName, Args),
delegate:call(QPid, {basic_consume, NoAck, ChPid, LimiterPid, LimiterActive,
ConsumerPrefetchCount, ConsumerTag, ExclusiveConsume,
Args, OkMsg}).
rabbit_amqqueue_process.erl
增加consumer,并更新到state中。
handle_call({basic_consume, NoAck, ChPid, LimiterPid, LimiterActive,
PrefetchCount, ConsumerTag, ExclusiveConsume, Args, OkMsg},
_From, State = #q{consumers = Consumers,
exclusive_consumer = Holder}) ->
case check_exclusive_access(Holder, ExclusiveConsume, State) of
in_use -> reply({error, exclusive_consume_unavailable}, State);
ok -> Consumers1 = rabbit_queue_consumers:add(
ChPid, ConsumerTag, NoAck,
LimiterPid, LimiterActive,
PrefetchCount, Args, is_empty(State),
Consumers),
ExclusiveConsumer =
if ExclusiveConsume -> {ChPid, ConsumerTag};
true -> Holder
end,
State1 = State#q{consumers = Consumers1,
has_had_consumers = true,
exclusive_consumer = ExclusiveConsumer},
ok = maybe_send_reply(ChPid, OkMsg),
emit_consumer_created(ChPid, ConsumerTag, ExclusiveConsume,
not NoAck, qname(State1),
PrefetchCount, Args, none),
notify_decorators(State1),
reply(ok, run_message_queue(State1))
end;
rabbit_queue_consumers.erl
更新进程字典,并为队列增加新消费者.
add(ChPid, CTag, NoAck, LimiterPid, LimiterActive, Prefetch, Args, IsEmpty,
State = #state{consumers = Consumers,
use = CUInfo}) ->
C = #cr{consumer_count = Count,
limiter = Limiter} = ch_record(ChPid, LimiterPid),
Limiter1 = case LimiterActive of
true -> rabbit_limiter:activate(Limiter);
false -> Limiter
end,
C1 = C#cr{consumer_count = Count + 1, limiter = Limiter1},
update_ch_record(
case parse_credit_args(Prefetch, Args) of
{0, auto} -> C1;
{_Credit, auto} when NoAck -> C1;
{Credit, Mode} -> credit_and_drain(
C1, CTag, Credit, Mode, IsEmpty)
end),
Consumer = #consumer{tag = CTag,
ack_required = not NoAck,
prefetch = Prefetch,
args = Args},
State#state{consumers = add_consumer({ChPid, Consumer}, Consumers),
use = update_use(CUInfo, active)}.
%%将consumer加入consumers列表里面,也就是后面分发消息的时候会从这个列表里将消息取出
in(X, 0, { queue, [_] = In, [], 1}) ->
{queue, [X], In, 2};
in(X, 0, {queue, In, Out, Len}) when is_list(In), is_list(Out) ->
{queue, [X|In], Out, Len + 1};
rabbitmq method之basic.consume的更多相关文章
- rabbitmq method之queue.declare
queue.declare即申请队列,首先对队列名作处理,若未指定队列名则随机生成一个,然后查询数据库队列是否已经创建,若创建完成则会申请队列返回 handle_method(#'queue.decl ...
- RabbitMQ channel 参数详解
1.Channel 1.1 channel.exchangeDeclare(): type:有direct.fanout.topic三种durable:true.false true:服务器重启会保留 ...
- RabbitMQ中客户端的Channel类里各方法释义
// The contents of this file are subject to the Mozilla Public License // Version 1.1 (the "Lic ...
- rabbitmq channel参数详解
文章转载自: https://www.cnblogs.com/piaolingzxh/p/5448927.html 部分参数说明有修改 1.Channel 1.1 channel.exchang ...
- rabbitmq channel参数详解【转】
1.Channel 1.1 channel.exchangeDeclare(): type:有direct.fanout.topic三种durable:true.false true:服务器重启会保留 ...
- RabbitMQ Consumer获取消息的两种方式(poll,subscribe)解析
以下转自:http://blog.csdn.net/yangbutao/article/details/10395599 rabbitMQ中consumer通过建立到queue的连接,创建channe ...
- RabbitMQ - Start Up
开始之前 rabbitmq是一个被广泛使用的消息队列,它是由erlang编写的,根据AMQP协议设计实现的. AMQP的主要特征是面向消息.队列.路由(包括点对点和发布/订阅).可靠性.安全. Rab ...
- 探索 OpenStack 之(14):OpenStack 中 RabbitMQ 的使用
本文是 OpenStack 中的 RabbitMQ 使用研究 两部分中的第一部分,将介绍 RabbitMQ 的基本概念,即 RabbitMQ 是什么.第二部分将介绍其在 OpenStack 中的使用. ...
- [译]rabbitmq 2.2 Building from the bottom: queues
我对rabbitmq学习还不深入,这些翻译仅仅做资料保存,希望不要误导大家. You have consumers and producers under your belt, and now you ...
随机推荐
- hmm
http://www.cnblogs.com/mindpuzzle/p/3653043.html http://en.wikipedia.org/wiki/Viterbi_algorithm http ...
- mysql 优化实例之索引创建
mysql 优化实例之索引创建 优化前: pt-query-degist分析结果: # Query 23: 0.00 QPS, 0.00x concurrency, ID 0x78761E301CC7 ...
- Effective C++阅读笔记_条款2:尽量以const,enum,inline替换#define
1.#define缺点1 #define NUM 1.2 记号NUM可能没有进入记号表,在调试或者错误信息中,无法知道1.2的含义. 改善:通过const int NUM = 1.2; 2.#dein ...
- <%#Eval if判断用法
1.绑定Repeater 基础用法 <%#Eval("RoleID")%> 2.简单判断用法 <td> <%# Convert.ToBoolean(E ...
- (2016弱校联盟十一专场10.3) A.Best Matched Pair
题目链接 #include<cstdio> #include<cstring> #include<algorithm> #include<stack> ...
- 模拟搭建Web项目的真实运行环境(一)
序言 最近尝试完整搭建一个Web项目的运行环境,总结一下这几个月学到的知识点. 后面的文章主要包括一下几个内容: A. 搭建一个Linux服务器,用来部署Redis.Mongo等数据存储环境: B. ...
- jasig CAS 实现单点登录 - java、php客户端登录实现
jasig CAS项目本身就是一个完整的CAS单点登录服务 1.服务端需要把 认证处理类.用户属性返回值处理类 调整成我们自己处理类即可实现单点登录 2.java客户端需要引入cas-client- ...
- 将Linux下的Android签名对pk8和pem转换为Eclipse下的签名(keystore)
一 在github上下载工具 https://github.com/getfatday/keytool-importkeypair 二 将工具在Linux环境下解压或者解压后Copy到Linux下,运 ...
- Pyqt 控件的信号槽事件定义方法
转载来自:http://my.oschina.net/midnite/blog/39399 Qt采用信号槽来设定UI界面上元素动作的事件绑定.自Qt4.5开始,引入了一个新的信号槽与事件绑定的方法.界 ...
- 犀利的报表系统,发票据与报表开发的快速利器,AgileEAS.NET SOA中间件GReport使用指南
一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...