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来作为队列名.

  1. handle_method(#'basic.consume'{queue = QueueNameBin,
  2. consumer_tag = ConsumerTag,
  3. no_local = _, % FIXME: implement
  4. no_ack = NoAck,
  5. exclusive = ExclusiveConsume,
  6. nowait = NoWait,
  7. arguments = Args},
  8. _, State = #ch{consumer_prefetch = ConsumerPrefetch,
  9. consumer_mapping = ConsumerMapping}) ->
  10. case dict:find(ConsumerTag, ConsumerMapping) of
  11. error ->
  12. QueueName = qbin_to_resource(QueueNameBin, State),
  13. check_read_permitted(QueueName, State),
  14. ActualConsumerTag =
  15. case ConsumerTag of
  16. <<>> -> rabbit_guid:binary(rabbit_guid:gen_secure(),
  17. "amq.ctag");
  18. Other -> Other
  19. end,
  20. case basic_consume(
  21. QueueName, NoAck, ConsumerPrefetch, ActualConsumerTag,
  22. ExclusiveConsume, Args, NoWait, State) of
  23. {ok, State1} ->
  24. {noreply, State1};
  25. {error, exclusive_consume_unavailable} ->
  26. rabbit_misc:protocol_error(
  27. access_refused, "~s in exclusive use",
  28. [rabbit_misc:rs(QueueName)])
  29. end;
  30. {ok, _} ->
  31. %% Attempted reuse of consumer tag.
  32. rabbit_misc:protocol_error(
  33. not_allowed, "attempt to reuse consumer tag '~s'", [ConsumerTag])
  34. end;
  1. basic_consume(QueueName, NoAck, ConsumerPrefetch, ActualConsumerTag,
  2. ExclusiveConsume, Args, NoWait,
  3. State = #ch{conn_pid = ConnPid,
  4. limiter = Limiter,
  5. consumer_mapping = ConsumerMapping}) ->
  6. case rabbit_amqqueue:with_exclusive_access_or_die(
  7. QueueName, ConnPid,
  8. fun (Q) ->
  9. {rabbit_amqqueue:basic_consume(
  10. Q, NoAck, self(),
  11. rabbit_limiter:pid(Limiter),
  12. rabbit_limiter:is_active(Limiter),
  13. ConsumerPrefetch, ActualConsumerTag,
  14. ExclusiveConsume, Args,
  15. ok_msg(NoWait, #'basic.consume_ok'{
  16. consumer_tag = ActualConsumerTag})),
  17. Q}
  18. end) of
  19. {ok, Q = #amqqueue{pid = QPid, name = QName}} ->
  20. CM1 = dict:store(
  21. ActualConsumerTag,
  22. {Q, {NoAck, ConsumerPrefetch, ExclusiveConsume, Args}},
  23. ConsumerMapping),
  24. State1 = monitor_delivering_queue(
  25. NoAck, QPid, QName,
  26. State#ch{consumer_mapping = CM1}),
  27. {ok, case NoWait of
  28. true -> consumer_monitor(ActualConsumerTag, State1);
  29. false -> State1
  30. end};
  31. {{error, exclusive_consume_unavailable} = E, _Q} ->
  32. E
  33. end.

rabbit_amqqueue.erl

rabbitmq_channel进程向rabbitmq_amqp_process进程发送消息来完成增加消费者的动作

  1. basic_consume(#amqqueue{pid = QPid, name = QName}, NoAck, ChPid, LimiterPid,
  2. LimiterActive, ConsumerPrefetchCount, ConsumerTag,
  3. ExclusiveConsume, Args, OkMsg) ->
  4. ok = check_consume_arguments(QName, Args),
  5. delegate:call(QPid, {basic_consume, NoAck, ChPid, LimiterPid, LimiterActive,
  6. ConsumerPrefetchCount, ConsumerTag, ExclusiveConsume,
  7. Args, OkMsg}).

rabbit_amqqueue_process.erl

增加consumer,并更新到state中。

  1. handle_call({basic_consume, NoAck, ChPid, LimiterPid, LimiterActive,
  2. PrefetchCount, ConsumerTag, ExclusiveConsume, Args, OkMsg},
  3. _From, State = #q{consumers = Consumers,
  4. exclusive_consumer = Holder}) ->
  5. case check_exclusive_access(Holder, ExclusiveConsume, State) of
  6. in_use -> reply({error, exclusive_consume_unavailable}, State);
  7. ok -> Consumers1 = rabbit_queue_consumers:add(
  8. ChPid, ConsumerTag, NoAck,
  9. LimiterPid, LimiterActive,
  10. PrefetchCount, Args, is_empty(State),
  11. Consumers),
  12. ExclusiveConsumer =
  13. if ExclusiveConsume -> {ChPid, ConsumerTag};
  14. true -> Holder
  15. end,
  16. State1 = State#q{consumers = Consumers1,
  17. has_had_consumers = true,
  18. exclusive_consumer = ExclusiveConsumer},
  19. ok = maybe_send_reply(ChPid, OkMsg),
  20. emit_consumer_created(ChPid, ConsumerTag, ExclusiveConsume,
  21. not NoAck, qname(State1),
  22. PrefetchCount, Args, none),
  23. notify_decorators(State1),
  24. reply(ok, run_message_queue(State1))
  25. end;

rabbit_queue_consumers.erl

更新进程字典,并为队列增加新消费者.

  1. add(ChPid, CTag, NoAck, LimiterPid, LimiterActive, Prefetch, Args, IsEmpty,
  2. State = #state{consumers = Consumers,
  3. use = CUInfo}) ->
  4. C = #cr{consumer_count = Count,
  5. limiter = Limiter} = ch_record(ChPid, LimiterPid),
  6. Limiter1 = case LimiterActive of
  7. true -> rabbit_limiter:activate(Limiter);
  8. false -> Limiter
  9. end,
  10. C1 = C#cr{consumer_count = Count + 1, limiter = Limiter1},
  11. update_ch_record(
  12. case parse_credit_args(Prefetch, Args) of
  13. {0, auto} -> C1;
  14. {_Credit, auto} when NoAck -> C1;
  15. {Credit, Mode} -> credit_and_drain(
  16. C1, CTag, Credit, Mode, IsEmpty)
  17. end),
  18. Consumer = #consumer{tag = CTag,
  19. ack_required = not NoAck,
  20. prefetch = Prefetch,
  21. args = Args},
  22. State#state{consumers = add_consumer({ChPid, Consumer}, Consumers),
  23. use = update_use(CUInfo, active)}.

%%将consumer加入consumers列表里面,也就是后面分发消息的时候会从这个列表里将消息取出

  1. in(X, 0, { queue, [_] = In, [], 1}) ->
  2. {queue, [X], In, 2};
  3. in(X, 0, {queue, In, Out, Len}) when is_list(In), is_list(Out) ->
  4. {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. Android编程容易犯的错误之二

    11.不要太相信工具,比如Eclipse里面的断点遇到多线程什么,经常不起作用/走不到,还有就是如果语句为空的也不会走,这时候别太早下结论断点地方出错了, 所以每个工程都应该有日志的开关,通过查看日志 ...

  2. sql 列转行

    原表:转过的表: 代码: ) set @sql = 'select AssetRecordId ' select @sql = @sql + ' , max(case ExtendName when ...

  3. @Controller和@RestController的区别

    1. Controller, RestController的共同点 都是用来表示spring某个类的是否可以接收HTTP请求 2.  Controller, RestController的不同点 @C ...

  4. Multiple dex files define Lcom/google/zxing/BarcodeFormat

    解决zxing “Could not find class 'com.goole.zxing.Result”和“Multiple dex files define”问题 时间 2014-04-24 1 ...

  5. 开发Visual Studio 插件

    新建项目,在其他项目类型中找到扩展性,然后新建Visual Studio外接程序,VS中没有这个要安装SDK,http://yunpan.cn/cd27eNczKREwd (提取码:ab29)去下载 ...

  6. windows批处理语法

    写批处理文件,除了了解基本语法外,你还需要熟悉常用的windows命令,那就先看看这篇文章:windows常用命令 #重要说明 文件及目录路径:要使用反斜杠'\',不要使用正斜杠'/' 如:del d ...

  7. JVM 1.6 GC

    JVM调优是一门艺术. JVM调优的重点是减少Major GC的次数,因为Major GC会暂停程序比较长的时间.如果Major GC的次数比较多,意味着应用程序的JVM内存参数需要调整. JVM内存 ...

  8. CS224d assignment 1【Neural Network Basics】

    refer to: 机器学习公开课笔记(5):神经网络(Neural Network) CS224d笔记3--神经网络 深度学习与自然语言处理(4)_斯坦福cs224d 大作业测验1与解答 CS224 ...

  9. lua52 C API测试代码

    //这是一篇lua与C++交互的情景测试 #include <lua.hpp> #include <lauxlib.h> #include <lualib.h> # ...

  10. 10 Cookie/Session

    JSP/EL入门     * SUN提供了开发WEB资源的技术     Servlet/JSP              * response.getWriter().write();         ...