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. js 的复制和引用 (传值和传址)

    复制(传值-实参):  基本类型赋值.函数参数 引用(传址-形参):  对象.数组.函数

  2. 使用SQL语句对数据进行MD5加密

    如果数据库表User中有一列为passwd,存放的是md5加密的数据,如何更新新的数据. update user set passwd=md5("123321") where uN ...

  3. Excel 导出

    admin = Context.Request.Cookies["user"].Values["username"].ToString();           ...

  4. NHibernate3快速上手教程FluentNHibernate配置与DBHelper

    很多学习NHibernate的新手很容易卡在配置文件这一关,正所谓万事开头难,上手后再配合官方文档就比较容易了. 网上关于配置文件的资料非常多,但由于版本的问题,许多老的教程中都没有明确指出类库的版本 ...

  5. c# 正则表达式用法

    C#正则表达式Regex类的用法 更多2014/2/18 来源:C#学习浏览量:41529 学习标签: 正则表达式 Regex 本文导读:正则表达式的本质是使用一系列特殊字符模式,来表示某一类字符串, ...

  6. NEFU 561 方块计算

    题目链接 简单搜索题 #include <cstdio> #include <iostream> #include <cstring> using namespac ...

  7. 会话控制:Cookie和session

    HTTP(超文本传输协议)定义了通过万维网(WWW)传输文本.图形.视频和所有其他数据所有的规则.HTTP是一种无状态的协议,说明每次请求的处理都与之前或之后的请求无关.虽然这种简化实现对于HTTP的 ...

  8. 在shell 上执行mongo 查询

    需求 在写小工具的时候,经常遇到需要从mongodb 里面查东西来用,因为要跟其他bash 工具链结合在一起用,所以最理想的方法是能够在shell 上执行查询,然后pipe 给接下来的工具做处理. 方 ...

  9. EventBus 一

    一.概述 EventBus是一款针对Android优化的发布/订阅事件总线.主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间 ...

  10. BurpSuite设置公共WIFI抓包

    1.电脑连接公共WIFI