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的更多相关文章

  1. rabbitmq method之queue.declare

    queue.declare即申请队列,首先对队列名作处理,若未指定队列名则随机生成一个,然后查询数据库队列是否已经创建,若创建完成则会申请队列返回 handle_method(#'queue.decl ...

  2. RabbitMQ channel 参数详解

    1.Channel 1.1 channel.exchangeDeclare(): type:有direct.fanout.topic三种durable:true.false true:服务器重启会保留 ...

  3. RabbitMQ中客户端的Channel类里各方法释义

    // The contents of this file are subject to the Mozilla Public License // Version 1.1 (the "Lic ...

  4. rabbitmq channel参数详解

    文章转载自: https://www.cnblogs.com/piaolingzxh/p/5448927.html    部分参数说明有修改 1.Channel 1.1 channel.exchang ...

  5. rabbitmq channel参数详解【转】

    1.Channel 1.1 channel.exchangeDeclare(): type:有direct.fanout.topic三种durable:true.false true:服务器重启会保留 ...

  6. RabbitMQ Consumer获取消息的两种方式(poll,subscribe)解析

    以下转自:http://blog.csdn.net/yangbutao/article/details/10395599 rabbitMQ中consumer通过建立到queue的连接,创建channe ...

  7. RabbitMQ - Start Up

    开始之前 rabbitmq是一个被广泛使用的消息队列,它是由erlang编写的,根据AMQP协议设计实现的. AMQP的主要特征是面向消息.队列.路由(包括点对点和发布/订阅).可靠性.安全. Rab ...

  8. 探索 OpenStack 之(14):OpenStack 中 RabbitMQ 的使用

    本文是 OpenStack 中的 RabbitMQ 使用研究 两部分中的第一部分,将介绍 RabbitMQ 的基本概念,即 RabbitMQ 是什么.第二部分将介绍其在 OpenStack 中的使用. ...

  9. [译]rabbitmq 2.2 Building from the bottom: queues

    我对rabbitmq学习还不深入,这些翻译仅仅做资料保存,希望不要误导大家. You have consumers and producers under your belt, and now you ...

随机推荐

  1. java17

    1:登录注册案例(理解) 2:Set集合(理解) (1)Set集合的特点 无序,唯一 (2)HashSet集合(掌握) A:底层数据结构是哈希表(是一个元素为链表的数组) B:哈希表底层依赖两个方法: ...

  2. hibernate中一对多关系中的inverse,cascade属性

    举例说明: 一对多关系的两张表:boy.girl(一个男孩可以多个女朋友) boy表结构 Field   Type        ------  -----------  name    varcha ...

  3. java ArrayList 实现

    关于ArrayList的实现和原理,原文出处:http://www.cnblogs.com/ITtangtang/p/3948555.html 我觉得他写的非常好,真的很好. 做一个记录和总结吧 pu ...

  4. CKEditor 配置

    在asp.net 中注意需要特殊处理控件的ID 先引入js <script type="text/javascript" src="ckeditor/ckedito ...

  5. 低功耗蓝牙BLE之连接事件、连接参数和更新方法

    转自:http://blog.csdn.net/zzfenglin/article/details/51304084 连接事件 在一个连接当中,主设备会在每个连接事件里向从设备发送数据包.一个连接事件 ...

  6. Java 初学记录之可执行jar包

    环境 jdk7 jre7 当我用jdk7开发的时候,编写完成可执行的jar工具,并且成功使用. 当我在另一台机器安装了jre6,再次运行我的小工具jar 的时候,报错 解决: http://stack ...

  7. C#写入和读出文本文件

    C#写入和读出文本文件 写入文本文件 class WriteTextFile { static void Main() { //如果文件不存在,则创建:存在则覆盖 //该方法写入字符数组换行显示 st ...

  8. jQuery对数据和对象的操作

    <script type="text/javascript" src="jquery-1.8.2.min.js"></script> & ...

  9. About_Return

    返回值:return return 表示从被调函数返回到主调函数继续执行,返回时可附带一个返回值,由return后面的参数指定. return通常是必要的,因为函数调用的时候计算结果通常是通过返回值带 ...

  10. 【转载】Linux 信号列表

    转自:http://blog.csdn.net/muge0913/article/details/7322710 信号及其简介 信号是一种进程通信的方法,他应用于异步事件的处理.信号的实现是一种软中断 ...