From 9c0025c9368103e7761c6b7605dbb18105808495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20G=C3=B6m=C3=B6ri?= Date: Mon, 31 Jul 2023 16:34:13 +0200 Subject: [PATCH] Only copy local listeners when FF listener_records_in_ets is enabled The `rabbit_listener_ets` table normally only contains listener entries for the local node. However after upgrading to 3.11.x and the `listener_records_in_ets` feature flag is enabled, all entries were copied to ETS from Mnesia, and the replicated Mnesia table contained entries for all nodes in a multi-node cluster. In this state `rabbit_networking:listener_of_protocol_ets/1` could crash with a case clause when multiple rows match a protocol. This can happen for example when the node is put in maintenance and the web_stomp plugin is enabled which queries the ranch refs to close all client connections. (rabbit_web_stomp_listener:close_all_client_connections)/1) A simple restart of the node or app reinitializes the listeners and the ETS table so this "corrupt" state is cleared. --- deps/rabbit/src/rabbit_core_ff.erl | 3 ++- deps/rabbit/src/rabbit_networking.erl | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/deps/rabbit/src/rabbit_core_ff.erl b/deps/rabbit/src/rabbit_core_ff.erl index 8eb0a731a566..d8023805688e 100644 --- a/deps/rabbit/src/rabbit_core_ff.erl +++ b/deps/rabbit/src/rabbit_core_ff.erl @@ -165,7 +165,8 @@ listener_records_in_ets_enable(#{feature_name := FeatureName}) -> rabbit_listener, [{'$1',[],['$1']}]), lists:foreach( fun(Listener) -> - ets:insert(rabbit_listener_ets, Listener) + rabbit_networking:is_listener_on_this_node(Listener) + andalso ets:insert(rabbit_listener_ets, Listener) end, Listeners) end) catch diff --git a/deps/rabbit/src/rabbit_networking.erl b/deps/rabbit/src/rabbit_networking.erl index 4d55c8253388..cf9904e497af 100644 --- a/deps/rabbit/src/rabbit_networking.erl +++ b/deps/rabbit/src/rabbit_networking.erl @@ -45,6 +45,8 @@ -export([ensure_listener_table_for_this_node/0]). +-export([is_listener_on_this_node/1]). + -deprecated([{force_connection_event_refresh, 1, eventually}]). -export([ @@ -819,3 +821,7 @@ ipv6_status(TestPort) -> ensure_listener_table_for_this_node() -> _ = ets:new(?ETS_TABLE, [named_table, public, bag, {keypos, #listener.node}]), ok. + +%% Needed for migration when feature flag listener_records_in_ets is enabled +is_listener_on_this_node(#listener{node = Node}) -> + Node =:= node().