Skip to content

Commit 6e7567e

Browse files
committed
Added sendig header for kafka message for Producer.
1 parent 903fcf3 commit 6e7567e

File tree

4 files changed

+46
-8
lines changed

4 files changed

+46
-8
lines changed

kafka/include/userver/kafka/producer.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <cstdint>
4+
#include <unordered_map>
45

56
#include <userver/engine/task/task_processor_fwd.hpp>
67
#include <userver/engine/task/task_with_result.hpp>
@@ -44,6 +45,9 @@ struct Secret;
4445
///
4546
/// @see https://docs.confluent.io/platform/current/clients/producer.html
4647
class Producer final {
48+
public:
49+
using Headers = std::unordered_map<std::string, std::string>;
50+
4751
public:
4852
/// @brief Creates the Kafka Producer.
4953
///
@@ -95,6 +99,7 @@ class Producer final {
9599
const std::string& topic_name,
96100
std::string_view key,
97101
std::string_view message,
102+
Headers headers = {},
98103
std::optional<std::uint32_t> partition = std::nullopt
99104
) const;
100105

@@ -111,6 +116,7 @@ class Producer final {
111116
std::string topic_name,
112117
std::string key,
113118
std::string message,
119+
Headers headers = {},
114120
std::optional<std::uint32_t> partition = std::nullopt
115121
) const;
116122

@@ -124,6 +130,7 @@ class Producer final {
124130
const std::string& topic_name,
125131
std::string_view key,
126132
std::string_view message,
133+
Headers headers = {},
127134
std::optional<std::uint32_t> partition
128135
) const;
129136

kafka/src/kafka/impl/producer_impl.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,11 @@ DeliveryResult ProducerImpl::Send(
126126
const std::string& topic_name,
127127
std::string_view key,
128128
std::string_view message,
129+
const Headers& headers,
129130
std::optional<std::uint32_t> partition
130131
) const {
131132
LOG_INFO() << fmt::format("Message to topic '{}' is requested to send", topic_name);
132-
auto delivery_result_future = ScheduleMessageDelivery(topic_name, key, message, partition);
133+
auto delivery_result_future = ScheduleMessageDelivery(topic_name, key, message, headers, partition);
133134

134135
WaitUntilDeliveryReported(delivery_result_future);
135136

@@ -140,6 +141,7 @@ engine::Future<DeliveryResult> ProducerImpl::ScheduleMessageDelivery(
140141
const std::string& topic_name,
141142
std::string_view key,
142143
std::string_view message,
144+
const Headers& headers,
143145
std::optional<std::uint32_t> partition
144146
) const {
145147
auto waiter = std::make_unique<DeliveryWaiter>();
@@ -173,13 +175,26 @@ engine::Future<DeliveryResult> ProducerImpl::ScheduleMessageDelivery(
173175
#pragma clang diagnostic ignored "-Wgnu-statement-expression"
174176
#endif
175177

178+
// We assume that message takes ownership of headers, if rd_kafka_producev()
179+
// succeeded. See rd_kafka RD_KAFKA_V_HEADERS reference for details
180+
struct KafkaHeaders final {
181+
using Ptr = std::unique_ptr<rd_kafka_headers_t, KafkaHeaders>;
182+
void operator()(rd_kafka_headers_t* headers) const { rd_kafka_headers_destroy(headers); }
183+
};
184+
185+
KafkaHeaders::Ptr kafka_headers{rd_kafka_headers_new(headers.size())};
186+
for (const auto& [header, value] : headers) {
187+
rd_kafka_header_add(kafka_headers.get(), header.c_str(), header.size(), value.c_str(), value.size());
188+
}
189+
176190
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDeleteLeaks,cppcoreguidelines-pro-type-const-cast)
177191
const rd_kafka_resp_err_t enqueue_error = rd_kafka_producev(
178192
producer_.GetHandle(),
179193
RD_KAFKA_V_TOPIC(topic_name.c_str()),
180194
RD_KAFKA_V_KEY(key.data(), key.size()),
181195
RD_KAFKA_V_VALUE(const_cast<char*>(message.data()), message.size()),
182196
RD_KAFKA_V_MSGFLAGS(0),
197+
RD_KAFKA_V_HEADERS(kafka_headers.get()),
183198
RD_KAFKA_V_PARTITION(partition.value_or(RD_KAFKA_PARTITION_UA)),
184199
RD_KAFKA_V_OPAQUE(waiter.get()),
185200
RD_KAFKA_V_END
@@ -191,6 +206,7 @@ engine::Future<DeliveryResult> ProducerImpl::ScheduleMessageDelivery(
191206
#endif
192207

193208
if (enqueue_error == RD_KAFKA_RESP_ERR_NO_ERROR) {
209+
[[maybe_unused]] const auto released = kafka_headers.release();
194210
[[maybe_unused]] auto _ = waiter.release();
195211
} else {
196212
LOG_WARNING(

kafka/src/kafka/impl/producer_impl.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <chrono>
44
#include <cstdint>
55
#include <optional>
6+
#include <unordered_map>
67

78
#include <librdkafka/rdkafka.h>
89

@@ -20,6 +21,9 @@ namespace kafka::impl {
2021
class Configuration;
2122

2223
class ProducerImpl final {
24+
public:
25+
using Headers = std::unordered_map<std::string, std::string>;
26+
2327
public:
2428
explicit ProducerImpl(Configuration&& configuration);
2529

@@ -31,6 +35,7 @@ class ProducerImpl final {
3135
const std::string& topic_name,
3236
std::string_view key,
3337
std::string_view message,
38+
const Headers& headers,
3439
std::optional<std::uint32_t> partition
3540
) const;
3641

@@ -51,6 +56,7 @@ class ProducerImpl final {
5156
const std::string& topic_name,
5257
std::string_view key,
5358
std::string_view message,
59+
const Headers& headers,
5460
std::optional<std::uint32_t> partition
5561
) const;
5662

kafka/src/kafka/producer.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,16 @@ void Producer::Send(
8686
const std::string& topic_name,
8787
std::string_view key,
8888
std::string_view message,
89+
Headers headers,
8990
std::optional<std::uint32_t> partition
9091
) const {
91-
utils::Async(producer_task_processor_, "producer_send", [this, &topic_name, key, message, partition] {
92-
SendImpl(topic_name, key, message, partition);
93-
}).Get();
92+
utils::Async(
93+
producer_task_processor_,
94+
"producer_send",
95+
[this, &topic_name, key, message, headers = std::move(headers), partition] {
96+
SendImpl(topic_name, key, headers, message, headers, partition);
97+
}
98+
).Get();
9499
}
95100

96101
engine::TaskWithResult<void> Producer::SendAsync(
@@ -102,9 +107,12 @@ engine::TaskWithResult<void> Producer::SendAsync(
102107
return utils::Async(
103108
producer_task_processor_,
104109
"producer_send_async",
105-
[this, topic_name = std::move(topic_name), key = std::move(key), message = std::move(message), partition] {
106-
SendImpl(topic_name, key, message, partition);
107-
}
110+
[this,
111+
topic_name = std::move(topic_name),
112+
key = std::move(key),
113+
message = std::move(message),
114+
headers = std::move(headers),
115+
partition] { SendImpl(topic_name, key, message, headers, partition); }
108116
);
109117
}
110118

@@ -114,11 +122,12 @@ void Producer::SendImpl(
114122
const std::string& topic_name,
115123
std::string_view key,
116124
std::string_view message,
125+
const Headers& headers,
117126
std::optional<std::uint32_t> partition
118127
) const {
119128
tracing::Span::CurrentSpan().AddTag("kafka_producer", name_);
120129

121-
const impl::DeliveryResult delivery_result = producer_->Send(topic_name, key, message, partition);
130+
const impl::DeliveryResult delivery_result = producer_->Send(topic_name, key, message, headers, partition);
122131
if (!delivery_result.IsSuccess()) {
123132
ThrowSendError(delivery_result);
124133
}

0 commit comments

Comments
 (0)