Closed hansehe closed 5 years ago
It would be possible to allow for alternative exchanges if the GetSubscriberAddresses() could be changed to the following:
public async Task<string[]> GetSubscriberAddresses(string topic) { if (topic.Contains("@")) { return new[] {topic}; } return new[] { $"{topic}@{_topicExchangeName}" }; }
Simple, but important
Looking at your PR, and thinking some more about this particular issue, I have these thoughts:
await bus.Advanced.Routing.Send("my-queue", message)
is expected to always send to a queue named "my-queue"
, it doesn't make sense to have separate exchanged of type=DIRECT – there should be one single exchange of type DIRECT, and it should have exactly one binding per queue that binds to routing keys with the same namesISubscriptionStorage
, being called just before RabbitMqTransport
's GetSubscriberAddresses
method)Regarding (1): Although, one might want to customize the exchange name, because of – who knows? – to avoid conflicts with existing stuff? Taste, even?
The current behavior (which I actually changed slightly in Rebus.RabbitMq 5.0.0-b06) is to treat
await bus.Advanced.Routing.Send("my-queue@random-exchange", someMessage);
as a genuine wish to send the message to the queue my-queue
, so the transport will check if the queue "my-queue"
exists (with QueueDeclarePassive
), and then check if the exchange "random-exchange"
exists (with ExchangeDeclarePassive
), and then lastly bind the topic "my-queue"
to the queue "my-queue"
(i.e. actually BIND the topic – it's not possible to check the existence of a binding with the C# driver).... this way, a sent message will not be lost if either queue, exchange, or binding has not been created beforehand.
This is done once for each queue/exchange combination that the bus instance sends to in its lifetime, so the time it takes is negligible.
Regarding (2): The reason it makes sense, is it makes it possible for exchanges to work as namespaces thus making is possible e.g. for different applications to do pub/sub without interfering with eachothers' events.
One could imagine something like
await bus.Publish(new AccountCreated(...));
happening in many types of otherwise unrelated applications, so I guess that's a good feature. One could even
await bus.Publish("an ordinary string!");
so supporting pub/sub with a global message broker could be messy, if exchanges could not be used to implement a scope for subscriptions.
QUEUE NAMES are global though, so if a broker instance is used for multiple applications, great care should be taken to ensure that queue names are unique across the entire world.
I think (2), (3), and (4) can be implemented simply by using the FullyQualifiedRoutingKey
class whenever a queue name/topic is to be handled, passing the default exchange name when the queue name/topic has not been exchange-qualified.
So... would you like to maybe make the adjustments to your PR?
Point 1 is already solved, as your saying, so yes please, I'll do the update to fulfill point 2, 3 and 4.
If I understand your opinion, I'll just simplify the code allowing for publishing to only one alternate exchange at a time.
And I gotta say, Rebus is great open source library!
Please have a look at the update to my PR. Simplified the code so that it is only possible to publish to one exchange at a time.
Fixed by #36 , which is out in Rebus.RabbitMq 5.0.0-b08 now 👍
Is it possible to extend the Rebus library to allow for sending messages on alternative exchanges, other then the default exchanges?
Example: Bus.Advanced.Routing.Send("alternativeExchange", "queue", message) Bus.Advanced.Topics("alternativeExchange", "topic", message)
Another alternative would be to use existing interface, but allow for setting which exchange to use with a simple routing topologi in the topic or destination address:
Example: Bus.Advanced.Routing.Send("queue@exchange", message) Bus.Advanced.Topics("topic@exchange", message)
Maybe it could be possible to use this topology for overriding which exchange to bind the topic?
Example: Bus.Advanced.Topics.Subscribe("topic@exchange")