Speaking of the message re-entering the queue also from the queue to register the consumer says, after the client registers the consumer with the queue, the channel created will also be monitor by the home column process, and when the channel is hung, the home column process (rabbit_amqqueue_process) receives ' Down ' notification, the message is re-entered into the queue, and the message is re-queued based on the deliver tag of the message, which is the order of consumption into the queue
The main code is as follows:
1. Registered Consumers
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-&G T QueueName = Qbin_to_resource (Queuenamebin, State), check_read_permitted (QueueName, state), Actualcon Sumertag = Case Consumertag of <<>>-Rabbit_guid:binary (rabbit_guid:ge N_secure (), "Amq.ctag"); Other, and other end, Case Basic_consume (QueueName, Noack, Consumerprefetch, Actualconsumertag, EXC Lusiveconsume, Args, NoWait, state) of {OK, State1}, {noreply, State1}; {error, exclusive_consume_unavailable}, Rabbit_misc:protocol_error (acce ss_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;
2. The home row process increases the consumer and monitors the channel process
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), end;
Ch_record (Chpid, Limiterpid) , Key = {ch, chpid}, Case get (Key) of undefined, monitorref = Erlang:mo Nitor (process, chpid), limiter = rabbit_limiter:client (limiterpid), C = #cr {ch_pid = chpid, monitor_ Ref = Monitorref, acktags = Queue:new (), consumer_count = 0, blocked_consumers = Priority_queue:new (), limiter = limiter, unsent_message_count = 0}, put (Key, c), C; c = #cr {} and C end.
3. After the home row process receives the channel ' down ' message, delete the consumer and get the message with this channel ACK
Handle_info ({' Down ', _monitorref, process, Downpid, _reason}, State)-Case Handle_ch_down (downpid, State) of< C1/>{ok, State1}, noreply (State1); {Stop, State1}, Stop (State1) end;
handle_ch_down (downpid, state = #q {consumers = consumers, Exclusive_consumer = Holder, senders = senders}), S tate1 = State#q{senders = Case pmon:is_monitored (downpid, senders) of false, Sender S True-Credit_flow:peer_down (Downpid), Pmon:demonitor (Downpid, senders) End}, Case Rabbit_queue_consumers:erase_ch (downpid, consumers) of Not_found {OK, State1}; {chacktags, chctags, Consumers1} case Should_auto_delete (State2) of True {stop, Sta TE2}; False, {OK, Requeue_and_run (Chacktags, Ensure_expiry_timer (State2))} End end.
4. When it comes to re-entering the queue, it is necessary to understand the backing queue, that is, how the message is on-demand between the mirrored queues and how the messages are switching between local memory and disk resources, or if this section involves more content, and post-order will specifically list a topic to analyze this implementation. The backing_queue of the Rabbit_amqqueue_process home column process is rabbit_mirror_queue_master (mirroring queue message synchronization), which is also backing_ because the message needs to be placed on demand. Queueu, namely Rabbit_variable_queue.
According to the sequeue_id to determine the position of the message in the queue, from the current queue pops out of the team header message (the first message into the queue), if the message is not ACK late (seqid relatively large), the queue of the pop team head and the message of the non-ACK is compared, The message POPs messages are placed in the front queue until they are met, the queue is inserted, and the front queue is combined with this queue.
Queue_merge (Seqids, Q, Msgids, Limit, Pubfun, State), Queue_merge (Seqids, Q,?) Queue:new (), Msgids, Limit, Pubfun, State). Queue_merge ([SeqId | Rest] = Seqids, Q, Front, Msgids, limit, pubfun, state) when limit = = undefined OrElse SeqId < limit Case? Queue:out (Q) of {{value, #msg_status {seq_id = seqidq} = msgstatus}, Q1} when SEQIDQ < SeqId Percent Enqueue from the remaining queue Queue_merge (Seqids, Q1,? Queue:in (Msgstatus, Front), Msgids, Limit, Pubfun, state); {_, _q1}, enqueue from the remaining list of sequence IDs {msgstatus, State1} = Msg_from_pen Ding_ack (SeqId, state), {#msg_status {msg_id = MsgId} = MsgStatus1, State2} = Pubfun (msgstatus , State1), Queue_merge (Rest, Q,?) Queue:in (MsgStatus1, Front), [MsgId | Msgids], Limit, Pubfun, State2) end;queue_merge (Seqids, Q, FRont, Msgids, _limit, _pubfun, state), {seqids,? Queue:join (Front, Q), Msgids, state}.
RABBITMQ message re-entry queue