Skip to content

DO NOT MERGE (needs signed CLA) Add a configurable limit for number of exchanges #14304

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

the-mikedavis
Copy link
Collaborator

@the-mikedavis the-mikedavis commented Jul 29, 2025

This is like @SimonUnge's past work for vhosts and queues but for limiting the total number of exchanges.

Vhosts and queues are more expensive since they run processes while exchanges are just metadata. A limit would be good for exchanges too though, because if you create a really large number of them you can increase the memory footprint by quite a bit - through taking more space in the metadata store and making more work for monitoring. By default the limit is unset and it can be enabled with cluster_exchange_limit = 100 or explicitly disabled with cluster_exchange_limit = infinity, like the vhost limit.

I've also added some small changes to the Khepri impls for rabbit_db_exchange's count/0 and exists/1 so that we use the projection ETS table rather than a query, to make this as cheap as possible.

@the-mikedavis the-mikedavis requested a review from SimonUnge July 29, 2025 15:38
@the-mikedavis the-mikedavis self-assigned this Jul 29, 2025
Comment on lines +151 to +158
case rabbit_db_exchange:exists(XName) of
true ->
%% Allow re-declares of existing exchanges when at the
%% exchange limit.
ok;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Note: allowing redeclares is important because if you reach the exchange limit and restart a Rabbit node, it will fail to boot due to the exchange declarations done in boot steps

@@ -105,6 +105,7 @@ serial(X) ->
Ret :: {ok, rabbit_types:exchange()} | {error, timeout}.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice! small comment, can we update the rabbit_exchange:declare/7 spec to reflect that this can now also return a channel exit / protocol error?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added no_return() here and a comment 👍

Note that this exit was possible before this change too if the exchange's validations failed:

%% called BEFORE declaration, to check args etc; may exit with #amqp_error{}
-callback validate(rabbit_types:exchange()) -> 'ok'.

(And this already logs a warning, so there's no need to also log in addition to exiting like we do for the vhost limit)

Copy link
Contributor

Choose a reason for hiding this comment

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

Cool. I was thinking rabbit_types:channel_exit() gives a bit more context here for the type? Can we use that instead?

-type(channel_exit() :: no_return()).

Copy link
Collaborator

@michaelklishin michaelklishin left a comment

Choose a reason for hiding this comment

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

exchange_max is not consistent with the queue equivalent, cluster_queue_limit. Perhaps this new setting should be named cluster_exchange_limit. This is a global limit.

Speaking of which, I guess we should also introduce a per-vhost limit as well? Possibly as a follow-up change.

@the-mikedavis
Copy link
Collaborator Author

Yeah adding per-vhost limits as a follow up sounds good to me.

The naming is a bit tricky: config options in this section tend to follow the <thing>_max formula whether they are scoped as per-node like connections or globally like vhosts. I don't have a strong opinion either way - the option name for queues is easy to understand

@michaelklishin
Copy link
Collaborator

*_max are some of the oldest settings RabbitMQ has. The closest limit equivalent is cluster_*_limit.

@michaelklishin
Copy link
Collaborator

@the-mikedavis thank you for renaming the setting.

I'm afraid we have to wait for a signed CLA to be returned to us by one of your colleagues, which is a work in progress and hopefully won't take too long.

@michaelklishin michaelklishin changed the title Add a configurable limit for number of exchanges DO NOT MERGE (needs signed CLA) Add a configurable limit for number of exchanges Jul 30, 2025
"exchange limit of ~b is reached",
[OverLimitXName, ?EXCHANGE_LIMIT])),
?assertExit(
{{shutdown, {server_initiated_close, 406, ExpectedError}}, _},
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not a big deal but I would not depend on a specific message in the test. The message can change, arguably the 406 PRECONDITION_FAILED response is all we care about.

However, I don't feel strongly about this.

These functions will be used in the child commit for a check on
the number of exchanges. We can use the projection to avoid bothering
the Khepri process with a query.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants