The rabbit_queue_type API has allowed to cancel a consumer.
Cancelling a consumer merely stops the queue sending more messages
to the consumer. However, messages checked out to the cancelled consumer
remain checked out until acked by the client. It's up to the client when
and whether it wants to ack the remaining checked out messages.
For AMQP 0.9.1, this behaviour is necessary because the client may
receive messages between the point in time it sends the basic.cancel
request and the point in time it receives the basic.cancel_ok response.
AMQP 1.0 is a better designed protocol because a receiver can stop a
link as shown in figure 2.46.
After a link is stopped, the client knows that the queue won't deliver
any more messages.
Once the link is stopped, the client can subsequently detach the link.
This commit extends the rabbit_queue_type API to allow a consumer being
immediately removed:
Any checked out messages to that receiver will be requeued by the
queue. (As explained previously, a client that first stops a link
by sending a FLOW with link_credit=0 and echo=true and waiting
for the FLOW reply from the server and settles any messages before
it sends the DETACH frame, won't have any checked out messages).
The queue entirely forgets this consumer and therefore stops
delivering messages to the receiver.
This new behaviour of consumer removal is similar to what happens when
an AMQP 0.9.1 channel is closed: All checked out messages to that
channel will be requeued.
Why?
Removing the consumer immediately simplifies many aspects:
The server session process doesn't need to requeue any checked out
messages for the receiver when the receiver detaches the link.
Specifically, messages in the outgoing_unsettled_map and
outgoing_pending queue don't need to be requeued because the queue
takes care of requeueing any checked out messages.
It simplifies reasoning about clients first detaching and then
re-attaching in the same session with the same link handle (the handle
becomes available for re-use once a link is closed): This will result
in the same RabbitMQ queue consumer tag.
It simplifies queue implementations since state needs to be hold and
special logic needs to be applied to consumers that are only
cancelled (basic.cancel AMQP 0.9.1) but not removed.
It makes the single active consumer feature safer when it comes to
maintaining message order: If a client cancels consumption via AMQP
0.9.1 basic.cancel, but still has in-flight checked out messages,
the queue will activate the next consumer. If the AMQP 0.9.1 client
shortly after crashes, messages to the old consumer will be requeued
which results in messages being out of order. To maintain message order,
an AMQP 0.9.1 client must close the whole channel such that messages
are requeued before the next consumer is activated.
For AMQP 1.0, the client can either stop the link first (preferred)
or detach the link directly. Detaching the link will requeue all
messages before activating the next consumer, therefore maintaining
message order. In this sense, the AMQP 1.0 implementation allows for the
single active consumer to gracefully handoff consumption to the next consumer.
Even if the session crashes, message order will be maintained.
How?
rabbit_queue_type:cancel accepts a spec as argument.
The new interaction between session proc and classic queue proc (let's
call it cancel API v2) must be hidden behind a feature flag.
This commit re-uses feature flag credit_api_v2 since it also gets
introduced in 4.0.
What?
The rabbit_queue_type API has allowed to cancel a consumer. Cancelling a consumer merely stops the queue sending more messages to the consumer. However, messages checked out to the cancelled consumer remain checked out until acked by the client. It's up to the client when and whether it wants to ack the remaining checked out messages.
For AMQP 0.9.1, this behaviour is necessary because the client may receive messages between the point in time it sends the basic.cancel request and the point in time it receives the basic.cancel_ok response.
AMQP 1.0 is a better designed protocol because a receiver can stop a link as shown in figure 2.46. After a link is stopped, the client knows that the queue won't deliver any more messages. Once the link is stopped, the client can subsequently detach the link.
This commit extends the rabbit_queue_type API to allow a consumer being immediately removed:
link_credit=0
andecho=true
and waiting for the FLOW reply from the server and settles any messages before it sends the DETACH frame, won't have any checked out messages).This new behaviour of consumer removal is similar to what happens when an AMQP 0.9.1 channel is closed: All checked out messages to that channel will be requeued.
Why?
Removing the consumer immediately simplifies many aspects:
It makes the single active consumer feature safer when it comes to maintaining message order: If a client cancels consumption via AMQP 0.9.1 basic.cancel, but still has in-flight checked out messages, the queue will activate the next consumer. If the AMQP 0.9.1 client shortly after crashes, messages to the old consumer will be requeued which results in messages being out of order. To maintain message order, an AMQP 0.9.1 client must close the whole channel such that messages are requeued before the next consumer is activated. For AMQP 1.0, the client can either stop the link first (preferred) or detach the link directly. Detaching the link will requeue all messages before activating the next consumer, therefore maintaining message order. In this sense, the AMQP 1.0 implementation allows for the single active consumer to gracefully handoff consumption to the next consumer. Even if the session crashes, message order will be maintained.
How?
rabbit_queue_type:cancel
accepts a spec as argument. The new interaction between session proc and classic queue proc (let's call it cancel API v2) must be hidden behind a feature flag. This commit re-uses feature flag credit_api_v2 since it also gets introduced in 4.0.