From dd5bed63080e71cce91057a079ae881a7574ae63 Mon Sep 17 00:00:00 2001 From: dcorbacho Date: Wed, 16 Sep 2020 12:38:55 +0100 Subject: [PATCH 1/5] Reclaim quorum memory command --- .../commands/reclaim_quorum_memory_command.ex | 53 +++++++++++++++++++ .../reclaim_quorum_memory_command_test.exs | 45 ++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex create mode 100644 deps/rabbitmq_cli/test/queues/reclaim_quorum_memory_command_test.exs diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex new file mode 100644 index 0000000000..ece9b32679 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex @@ -0,0 +1,53 @@ +## This Source Code Form is subject to the terms of the Mozilla Public +## License, v. 2.0. If a copy of the MPL was not distributed with this +## file, You can obtain one at https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. + +defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand do + alias RabbitMQ.CLI.Core.DocGuide + + @behaviour RabbitMQ.CLI.CommandBehaviour + def scopes(), do: [:diagnostics, :queues] + + def merge_defaults(args, opts), do: {args, Map.merge(%{vhost: "/"}, opts)} + + use RabbitMQ.CLI.Core.AcceptsOnePositionalArgument + use RabbitMQ.CLI.Core.RequiresRabbitAppRunning + + def run([name] = _args, %{node: node_name, vhost: vhost}) do + case :rabbit_misc.rpc_call(node_name, :rabbit_quorum_queue, :reclaim_memory, [vhost, name]) do + {:error, :classic_queue_not_supported} -> + {:error, "Cannot reclaim memory of a classic queue"} + + other -> + other + end + end + + use RabbitMQ.CLI.DefaultOutput + + def usage() do + "reclaim_quorum_memory [--vhost ] " + end + + def usage_additional do + [ + ["", "Name of the queue"] + ] + end + + def usage_doc_guides() do + [ + DocGuide.quorum_queues(), + DocGuide.memory_use() + ] + end + + def help_section(), do: :operations + + def description(), do: "Makes all Erlang processes used by a quorum queue perform a full sweep garbage collection and flush of the WAL" + + def banner([name], %{}), + do: "Reclaim memory used by quorum queue #{name} ..." +end diff --git a/deps/rabbitmq_cli/test/queues/reclaim_quorum_memory_command_test.exs b/deps/rabbitmq_cli/test/queues/reclaim_quorum_memory_command_test.exs new file mode 100644 index 0000000000..bec7bab50d --- /dev/null +++ b/deps/rabbitmq_cli/test/queues/reclaim_quorum_memory_command_test.exs @@ -0,0 +1,45 @@ +## This Source Code Form is subject to the terms of the Mozilla Public +## License, v. 2.0. If a copy of the MPL was not distributed with this +## file, You can obtain one at https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. + +defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommandTest do + use ExUnit.Case, async: false + import TestHelper + + @command RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand + + setup_all do + RabbitMQ.CLI.Core.Distribution.start() + + :ok + end + + setup context do + {:ok, opts: %{ + node: get_rabbit_hostname(), + timeout: context[:test_timeout] || 30000 + }} + end + + + test "validate: treats no arguments as a failure" do + assert @command.validate([], %{}) == {:validation_failure, :not_enough_args} + end + + test "validate: accepts a single positional argument" do + assert @command.validate(["quorum-queue-a"], %{}) == :ok + end + + test "validate: when two or more arguments are provided, returns a failure" do + assert @command.validate(["quorum-queue-a", "one-extra-arg"], %{}) == {:validation_failure, :too_many_args} + assert @command.validate(["quorum-queue-a", "extra-arg", "another-extra-arg"], %{}) == {:validation_failure, :too_many_args} + end + + @tag test_timeout: 3000 + test "run: targeting an unreachable node throws a badrpc" do + assert match?({:badrpc, _}, @command.run(["quorum-queue-a"], + %{node: :jake@thedog, vhost: "/", timeout: 200})) + end +end From 9ba1f594f7bcb0f9dd57db3ce16e26bcbd5c4b02 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2020 08:15:42 +0300 Subject: [PATCH 2/5] Wording --- .../cli/queues/commands/reclaim_quorum_memory_command.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex index ece9b32679..ed11e9d37b 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex @@ -28,12 +28,12 @@ defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand do use RabbitMQ.CLI.DefaultOutput def usage() do - "reclaim_quorum_memory [--vhost ] " + "reclaim_quorum_memory " end def usage_additional do [ - ["", "Name of the queue"] + ["", "Name of the quorum queue"] ] end @@ -46,8 +46,8 @@ defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand do def help_section(), do: :operations - def description(), do: "Makes all Erlang processes used by a quorum queue perform a full sweep garbage collection and flush of the WAL" + def description(), do: "Flushes quorum queue processes WAL, performs a full sweep GC on all of its local Erlang processes" def banner([name], %{}), - do: "Reclaim memory used by quorum queue #{name} ..." + do: "Will flush Raft WAL of quorum queue #{name} ..." end From a6e17863fb8b766ba07b39f81beac2c8850038d1 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2020 10:00:52 +0300 Subject: [PATCH 3/5] Introduce RabbitMQ.CLI.Core.MergesDefaultVirtualHost Despite being the implicit default, the "/" virtual host may be required in function assertions, so an explicit merge can still be necessary. Lets introduce a reusable macro module for this. --- .../cli/core/merges_default_virtual_host.ex | 15 +++++++++++++++ .../commands/reclaim_quorum_memory_command.ex | 3 +-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 deps/rabbitmq_cli/lib/rabbitmq/cli/core/merges_default_virtual_host.ex diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/core/merges_default_virtual_host.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/core/merges_default_virtual_host.ex new file mode 100644 index 0000000000..94b1b768b6 --- /dev/null +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/core/merges_default_virtual_host.ex @@ -0,0 +1,15 @@ +## This Source Code Form is subject to the terms of the Mozilla Public +## License, v. 2.0. If a copy of the MPL was not distributed with this +## file, You can obtain one at https://mozilla.org/MPL/2.0/. +## +## Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved. + +# Should be used by commands that require rabbit app to be stopped +# but need no other execution environment validators. +defmodule RabbitMQ.CLI.Core.MergesDefaultVirtualHost do + defmacro __using__(_) do + quote do + def merge_defaults(args, opts), do: {args, Map.merge(%{vhost: "/"}, opts)} + end + end +end diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex index ed11e9d37b..12d5094ce3 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex @@ -10,8 +10,7 @@ defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand do @behaviour RabbitMQ.CLI.CommandBehaviour def scopes(), do: [:diagnostics, :queues] - def merge_defaults(args, opts), do: {args, Map.merge(%{vhost: "/"}, opts)} - + use RabbitMQ.CLI.Core.MergesDefaultVirtualHost use RabbitMQ.CLI.Core.AcceptsOnePositionalArgument use RabbitMQ.CLI.Core.RequiresRabbitAppRunning From f16166d29b2638d0b7e31a43b82174a84a8103ba Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2020 10:18:11 +0300 Subject: [PATCH 4/5] rabbitmq-queues reclaim_quorum_memory: restore --vhost mention in usage apparently quite a few commands have it, even though it's documented in the general/global parameters section. --- .../cli/queues/commands/reclaim_quorum_memory_command.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex index 12d5094ce3..5afc0d5360 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex @@ -27,7 +27,7 @@ defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand do use RabbitMQ.CLI.DefaultOutput def usage() do - "reclaim_quorum_memory " + "reclaim_quorum_memory [--vhost ] " end def usage_additional do From 28a5f4fc45accab319680008a2e710d68081da97 Mon Sep 17 00:00:00 2001 From: Michael Klishin Date: Fri, 18 Sep 2020 11:58:15 +0300 Subject: [PATCH 5/5] Improve error handling, including with --formatter=json --- .../commands/reclaim_quorum_memory_command.ex | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex index 5afc0d5360..3452cc8741 100644 --- a/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex +++ b/deps/rabbitmq_cli/lib/rabbitmq/cli/queues/commands/reclaim_quorum_memory_command.ex @@ -17,13 +17,30 @@ defmodule RabbitMQ.CLI.Queues.Commands.ReclaimQuorumMemoryCommand do def run([name] = _args, %{node: node_name, vhost: vhost}) do case :rabbit_misc.rpc_call(node_name, :rabbit_quorum_queue, :reclaim_memory, [vhost, name]) do {:error, :classic_queue_not_supported} -> - {:error, "Cannot reclaim memory of a classic queue"} + {:error, "This operation is not applicable to classic queues"} other -> other end end + def output({:error, :not_found}, %{vhost: vhost, formatter: "json"}) do + {:error, + %{ + "result" => "error", + "message" => "Target queue was not found in virtual host '#{vhost}'" + }} + end + def output({:error, error}, %{formatter: "json"}) do + {:error, + %{ + "result" => "error", + "message" => "Failed to perform the operation: #{error}" + }} + end + def output({:error, :not_found}, %{vhost: vhost}) do + {:error, "Target queue was not found in virtual host '#{vhost}'"} + end use RabbitMQ.CLI.DefaultOutput def usage() do