Skip to content

[Messenger] Ability to distinguish retry and delay actions #36864

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 10, 2021

Conversation

theravel
Copy link
Contributor

@theravel theravel commented May 18, 2020

Added ability to distinguish retry and delay actions so that different "x-dead-letter-exchange" exchange name will be used in different scenarios.

Q A
Branch? 5.x
Bug fix? no
New feature? yes
Deprecations? no
Tickets -
License MIT
Doc PR

This is a bug which existed since v4.4. The following scenario is possible:

  • There are two queues: A and B, both are bound to the same routing key via "topic" exchange (two different applications for example).
  • A message is published to this routing key to "topic" exchange.
  • Consumer of queue A handles it correctly and acknowledges the message.
  • Consumer of queue B throws and exception and message goes to retry (for example to queue delay_delays_key_5).
  • Once message expired in delay_delays_key_5, it is delivered again to both A and B (again consumed by consumer A).

Expected: behavior of consumer B should not cause message duplication to queue A.

It is required to make a change of name of temporary delay queue (otherwise "delay" and "retry" queues have incompatible declaration arguments). I left queue_name_pattern as is to keep settings of connection backward compatible, but changed internals of queue name construction.

@theravel theravel requested a review from sroze as a code owner May 18, 2020 23:47
@theravel theravel force-pushed the fix-retry-broadcasting branch from 102bf8e to f6e8c45 Compare May 18, 2020 23:49
@theravel theravel changed the title Ability to distinguish retry and delay actions [Messenger] Ability to distinguish retry and delay actions May 18, 2020
@nicolas-grekas nicolas-grekas added this to the 4.4 milestone May 19, 2020
@nicolas-grekas
Copy link
Member

In my implementation I could not avoid minor incompatible change: queue_name_pattern has changed, so looks like this cannot be released under 4.4 or 5.0. Can we include it into 5.1 please?

Neither would this be allowed in master since it would break apps migrating to 5.2. Can we find another idea?

@theravel theravel force-pushed the fix-retry-broadcasting branch from 798e402 to d3124bf Compare May 19, 2020 09:01
@theravel
Copy link
Contributor Author

theravel commented May 19, 2020

Neither would this be allowed in master since it would break apps migrating to 5.2. Can we find another idea?

@nicolas-grekas Thank you for the feedback. I changed it: now queue_name_pattern remains backward compatible, but I changed internals of queue name construction.

Should I change target branch in this case?

@nicolas-grekas
Copy link
Member

Yes please if this should be considered as a bugfix (I didn't check that part).

@theravel theravel force-pushed the fix-retry-broadcasting branch from d3124bf to aa81532 Compare May 19, 2020 22:18
@theravel theravel changed the base branch from master to 4.4 May 19, 2020 22:19
@theravel
Copy link
Contributor Author

@nicolas-grekas changed target to 4.4

Tobion
Tobion previously requested changes May 23, 2020
@@ -45,7 +46,12 @@ public function getAttributes(): array
return $this->attributes;
}

public static function createFromAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, self $previousStamp = null): self
public function isEnvelopeRedelivered(): bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really confusing. AMQP also has the concept of redelivery. But this is not the same as the redelivery in the messenger component. Since this is the stamp to encode the amqp flags, this is really unexpected. So this needs a different name or not be exposed at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been renamed

@Tobion
Copy link
Contributor

Tobion commented May 23, 2020

#36196 and #36212 already try to solve the same problem.

@s-code
Copy link

s-code commented May 28, 2020

@theravel i was able to solve this and few other problems without changing Messenger connection class, but it's little bit tricky. Here is an example https://github.com/s-code/amqp-extra-bundle. Take a look on ExtraAmqpFactory, ExtraAmqpSender, ExtraAmqpQueue, ExtraAmqpExchange.
As for me, splitting of retry and delay logic is a must have for amqp transport.

@weaverryan
Copy link
Member

On a high level, this makes sense to me:

If a message is in queue A, and I read it from queue A and it fails, then it should go back onto queue A only.

Messenger handles retries by actually ack'ing the original message and redelivering it. But ultimately, the desired behavior (I think) would be what I described above and what this PR does.

Though, apparently this and #38486 solve the same problem (is it the exact same problem?) but in different ways. @s-code could you comment on what your PR does versus this one?

Thanks :)

@s-code
Copy link

s-code commented Oct 22, 2020

@weaverryan you are right. This two pull requests solve the same problem. The difference is in next things:

  1. Delay queue naming convention.
  1. [Messenger] Add possibility to route delayed messages to the origin queue directly #38486 allows to use default exchange for delay and retry logic. If in configuration we define delay.exchange_name as '', no extra ("delays") exchange will be created. For me it's more elegant and clean solution

@theravel theravel requested a review from nicolas-grekas April 11, 2021 22:43
@nicolas-grekas
Copy link
Member

(please add a changelog entry in the bridge)

@theravel
Copy link
Contributor Author

@nicolas-grekas Changelog entry added

Copy link
Member

@Nyholm Nyholm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im happy with this. Just one question

@@ -45,7 +46,7 @@ public function getAttributes(): array
return $this->attributes;
}

public static function createFromAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, self $previousStamp = null): self
public static function createFromAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, self $previousStamp = null, string $retryRoutingKey = null): self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using $amqpReceivedStamp->getQueueName() to populate the $retryRoutingKey, is that really correct?

A routing key is not the same as the queue name.

(It is probably correct, but I just need you to clarify.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct. We want to distinguish:

  • delay scenario, where message should be sent to original exchange to original routing key (so that all consumers can get it)
  • retry scenario, where message should be sent to default (direct) exchange to routing key which matches queue name (in this case it will be received in one queue only)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure the routing key always matches the queue name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For direct exchange in AMQP 0-9-1 yes:

The default exchange is a direct exchange with no name (empty string) pre-declared by the broker. It has one special property that makes it very useful for simple applications: every queue that is created is automatically bound to it with a routing key which is the same as the queue name.

See https://www.rabbitmq.com/tutorials/amqp-concepts.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nyholm can you review please?

@theravel theravel requested a review from Nyholm April 21, 2021 13:39
@MichaelKubovic
Copy link

MichaelKubovic commented Apr 21, 2021 via email

@Nyholm
Copy link
Member

Nyholm commented May 10, 2021

Thank you @theravel and @MichaelKubovic for confirming.

@Nyholm Nyholm force-pushed the fix-retry-broadcasting branch from 35a6ada to 417aaab Compare May 10, 2021 20:46
@Nyholm
Copy link
Member

Nyholm commented May 10, 2021

Thank your for this feature. Please update the docs too =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants