Skip to content

Commit 031ebc8

Browse files
authored
Merge pull request #109 from cloudamqp/support_3_13
Support message containers introduced in RabbitMQ 3.13.0
2 parents 2591f9d + 415e16e commit 031ebc8

File tree

7 files changed

+43
-54
lines changed

7 files changed

+43
-54
lines changed

.github/workflows/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
elixir:
1111
- '1.16.3'
1212
rmqref:
13-
- v3.12.x
13+
- v3.13.x
1414
steps:
1515
- uses: actions/checkout@v4
1616
- name: Install Erlang and Elixir

Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
PROJECT = rabbitmq_message_deduplication
2+
PROJ_VSN = $(shell $(MIX) eval 'Mix.Project.config()[:version] |> IO.puts()')
23

34
DEPS = rabbit_common rabbit
45
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client
@@ -25,15 +26,15 @@ app:: $(elixir_srcs) deps
2526

2627
dist:: app
2728
mkdir -p $(DIST_DIR)
28-
$(MIX) make_archives
29+
$(MIX) archive.build.elixir
30+
$(MIX) archive.build -o $(DIST_DIR)/$(PROJECT)-$(PROJ_VSN).ez
2931
cp -r _build/$(MIX_ENV)/archives/elixir-*.ez $(DIST_DIR)
30-
cp -r _build/$(MIX_ENV)/archives/$(PROJECT)-*.ez $(DIST_DIR)
3132

3233
test-build:: app
3334
mkdir -p $(DIST_DIR)
34-
$(MIX) make_archives
35+
$(MIX) archive.build.elixir
36+
$(MIX) archive.build -o $(DIST_DIR)/$(PROJECT)-$(PROJ_VSN).ez
3537
cp -r _build/$(MIX_ENV)/archives/elixir-*.ez $(DIST_DIR)
36-
cp -r _build/$(MIX_ENV)/archives/$(PROJECT)-*.ez $(DIST_DIR)
3738

3839
tests:: $(elixir_srcs) deps
3940
MIX_ENV=test $(MIX) make_tests

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ Then copy all the *.ez files inside the plugins folder to the [RabbitMQ plugins
3636
[sudo] rabbitmq-plugins enable rabbitmq_message_deduplication
3737
```
3838

39+
## Version requirements
40+
41+
The latest version of the plugin requires RabbitMQ 3.13.0.
42+
43+
Earlier RabbitMQ versions are supported by 0.6.2.
44+
3945
## Exchange level deduplication
4046

4147
The exchange type `x-message-deduplication` allows to filter message duplicates before any routing rule is applied.

lib/rabbitmq_message_deduplication/common.ex

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,11 @@ defmodule RabbitMQMessageDeduplication.Common do
1212
1313
"""
1414

15-
import Record, only: [defrecord: 2, defrecord: 3, extract: 2]
16-
1715
require RabbitMQMessageDeduplication.Cache
1816

19-
alias :rabbit_binary_parser, as: RabbitBinaryParser
17+
alias :mc, as: MC
2018
alias RabbitMQMessageDeduplication.Cache, as: Cache
2119

22-
defrecord :content, extract(
23-
:content, from_lib: "rabbit_common/include/rabbit.hrl")
24-
25-
@type basic_message :: record(:basic_message)
26-
defrecord :basic_message, extract(
27-
:basic_message, from_lib: "rabbit_common/include/rabbit.hrl")
28-
29-
defrecord :basic_properties, :P_basic, extract(
30-
:P_basic, from_lib: "rabbit_common/include/rabbit_framing.hrl")
31-
3220
@default_arguments %{type: nil, default: nil}
3321

3422
@doc """
@@ -55,14 +43,24 @@ defmodule RabbitMQMessageDeduplication.Common do
5543
@doc """
5644
Retrieve the given header from the message.
5745
"""
58-
@spec message_header(basic_message, String.t) :: String.t | nil
59-
def message_header(basic_message(content: message_content), header) do
60-
message_content = RabbitBinaryParser.ensure_content_decoded(message_content)
61-
62-
case content(message_content, :properties) do
63-
basic_properties(headers: headers) when is_list(headers) ->
64-
rabbit_keyfind(headers, header)
65-
basic_properties(headers: :undefined) -> nil
46+
@spec message_header(MC.state, String.t) :: String.t | integer() | float() | boolean() | :undefined | nil
47+
def message_header(message, header) do
48+
case MC.x_header(header, message) do
49+
{_type, value} when not is_list(value) and not is_tuple(value) ->
50+
# list and tuple values have type-tagged elements
51+
# that would need to be untagged recursively
52+
# we don't expect to use such headers, so those cases are not handled
53+
value
54+
:null ->
55+
# header value in AMQP message was {:void, :undefined}
56+
57+
# pre-3.13 version of this function used rabbit_keyfind/2
58+
# which returned :undefined instead of nil or :void. We have to
59+
# keep this value as this is used in keys to cache the message
60+
# and is preserved during a rolling upgrade in a replicated
61+
# Mnesia table
62+
:undefined
63+
:undefined -> nil
6664
end
6765
end
6866

@@ -71,7 +69,7 @@ defmodule RabbitMQMessageDeduplication.Common do
7169
7270
If not, it adds it to the cache with the corresponding name.
7371
"""
74-
@spec duplicate?(tuple, basic_message, integer | nil) :: boolean
72+
@spec duplicate?(tuple, MC.state, integer | nil) :: boolean
7573
def duplicate?(name, message, ttl \\ nil) do
7674
cache = cache_name(name)
7775

lib/rabbitmq_message_deduplication/rabbit_message_deduplication_exchange.ex

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,6 @@ defmodule RabbitMQMessageDeduplication.Exchange do
5353
defrecord :exchange, extract(
5454
:exchange, from_lib: "rabbit_common/include/rabbit.hrl")
5555

56-
defrecord :delivery, extract(
57-
:delivery, from_lib: "rabbit_common/include/rabbit.hrl")
58-
59-
defrecord :basic_message, extract(
60-
:basic_message, from_lib: "rabbit_common/include/rabbit.hrl")
61-
6256
@doc """
6357
Register the exchange type within the Broker.
6458
"""
@@ -90,7 +84,7 @@ defmodule RabbitMQMessageDeduplication.Exchange do
9084
end
9185

9286
@impl :rabbit_exchange_type
93-
def route(exchange(name: name), delivery(message: msg = basic_message())) do
87+
def route(exchange(name: name), msg, _opts) do
9488
if route?(name, msg) do
9589
RabbitRouter.match_routing_key(name, [:_])
9690
else

lib/rabbitmq_message_deduplication/rabbit_message_deduplication_queue.ex

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ defmodule RabbitMQMessageDeduplication.Queue do
2222
2323
"""
2424

25-
import Record, only: [defrecord: 2, defrecord: 3, extract: 2]
25+
import Record, only: [defrecord: 2]
2626

2727
require RabbitMQMessageDeduplication.Cache
2828
require RabbitMQMessageDeduplication.Common
2929

3030
alias :amqqueue, as: AMQQueue
3131
alias :rabbit_log, as: RabbitLog
3232
alias :rabbit_amqqueue, as: RabbitQueue
33+
alias :mc, as: MC
3334
alias RabbitMQMessageDeduplication.Common, as: Common
3435
alias RabbitMQMessageDeduplication.Cache, as: Cache
3536
alias RabbitMQMessageDeduplication.CacheManager, as: CacheManager
@@ -46,15 +47,6 @@ defmodule RabbitMQMessageDeduplication.Queue do
4647
{:requires, :kernel_ready},
4748
{:enables, :core_initialized}]}
4849

49-
defrecord :content, extract(
50-
:content, from_lib: "rabbit_common/include/rabbit.hrl")
51-
52-
defrecord :basic_message, extract(
53-
:basic_message, from_lib: "rabbit_common/include/rabbit.hrl")
54-
55-
defrecord :basic_properties, :P_basic, extract(
56-
:P_basic, from_lib: "rabbit_common/include/rabbit_framing.hrl")
57-
5850
defrecord :dqack, [:tag, :header]
5951
defrecord :dqstate, [:queue, :queue_state, dedup_enabled: false]
6052

@@ -286,8 +278,9 @@ defmodule RabbitMQMessageDeduplication.Queue do
286278
if dedup_queue?(state) do
287279
case fetch(need_ack, state) do
288280
{:empty, state} -> {:empty, state}
289-
{{message = basic_message(id: id), _, ack_tag}, state} ->
281+
{{message, _, ack_tag}, state} ->
290282
maybe_delete_cache_entry(queue, message)
283+
id = MC.get_annotation(:id, message)
291284

292285
{{id, ack_tag}, state}
293286
end
@@ -521,7 +514,7 @@ defmodule RabbitMQMessageDeduplication.Queue do
521514
end
522515

523516
# Returns true if the message is a duplicate.
524-
defp duplicate?(queue, message = basic_message()) do
517+
defp duplicate?(queue, message) do
525518
name = AMQQueue.get_name(queue)
526519

527520
if Common.duplicate?(name, message, message_expiration(message)) do
@@ -533,18 +526,14 @@ defmodule RabbitMQMessageDeduplication.Queue do
533526

534527
# Returns the expiration property of the given message
535528
defp message_expiration(message) do
536-
basic_message(content: content(properties: properties)) = message
537-
538-
case properties do
539-
basic_properties(expiration: ttl) when is_bitstring(ttl) ->
540-
String.to_integer(ttl)
541-
basic_properties(expiration: :undefined) -> nil
529+
case MC.ttl(message) do
542530
:undefined -> nil
531+
ttl -> ttl
543532
end
544533
end
545534

546535
# Removes the message deduplication header from the cache
547-
defp maybe_delete_cache_entry(queue, msg = basic_message()) do
536+
defp maybe_delete_cache_entry(queue, msg) when is_tuple(msg) do
548537
header = Common.message_header(msg, "x-deduplication-header")
549538
maybe_delete_cache_entry(queue, header)
550539
end

mix.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ defmodule RabbitMQ.MessageDeduplicationPlugin.Mixfile do
1818
applications: [:mnesia],
1919
extra_applications: [:rabbit],
2020
mod: {RabbitMQMessageDeduplication, []},
21-
registered: [RabbitMQMessageDeduplication]
21+
registered: [RabbitMQMessageDeduplication],
22+
broker_version_requirements: ["3.13.0"]
2223
]
2324
end
2425

0 commit comments

Comments
 (0)