77#include < userver/testsuite/testpoint.hpp>
88#include < userver/tracing/span.hpp>
99#include < userver/utils/async.hpp>
10+ #include < userver/utils/span.hpp>
1011#include < userver/utils/text_light.hpp>
1112
1213#include < kafka/impl/producer_impl.hpp>
@@ -54,26 +55,52 @@ void SendToTestPoint(
5455 }());
5556}
5657
57- [[noreturn]] void ThrowSendError (const impl::DeliveryResult& delivery_result) {
58+ std::exception_ptr BuildSendError (const impl::DeliveryResult& delivery_result) {
5859 const auto error = delivery_result.GetMessageError ();
5960 UASSERT (error != RD_KAFKA_RESP_ERR_NO_ERROR);
6061
6162 switch (error) {
6263 case RD_KAFKA_RESP_ERR__MSG_TIMED_OUT:
63- throw DeliveryTimeoutException{};
64+ return std::make_exception_ptr ( DeliveryTimeoutException{}) ;
6465 case RD_KAFKA_RESP_ERR__QUEUE_FULL:
65- throw QueueFullException{};
66+ return std::make_exception_ptr ( QueueFullException{}) ;
6667 case RD_KAFKA_RESP_ERR_MSG_SIZE_TOO_LARGE:
67- throw MessageTooLargeException{};
68+ return std::make_exception_ptr ( MessageTooLargeException{}) ;
6869 case RD_KAFKA_RESP_ERR__UNKNOWN_TOPIC:
69- throw kafka:: UnknownTopicException{};
70+ return std::make_exception_ptr ( UnknownTopicException{}) ;
7071 case RD_KAFKA_RESP_ERR__UNKNOWN_PARTITION:
71- throw kafka:: UnknownPartitionException{};
72+ return std::make_exception_ptr ( UnknownPartitionException{}) ;
7273 default :
73- throw kafka::SendException{rd_kafka_err2str (error)};
74+ return std::make_exception_ptr (SendException{rd_kafka_err2str (error)});
75+ }
76+ }
77+
78+ [[noreturn]] void ThrowSendError (const impl::DeliveryResult& delivery_result) {
79+ std::rethrow_exception (BuildSendError (delivery_result));
80+ }
81+
82+ auto BuildOwningHeaders (const impl::HeadersHolder& headers) {
83+ auto reader = HeadersReader{headers.GetHandle ()};
84+ return std::vector<OwningHeader>{reader.begin (), reader.end ()};
85+ }
86+
87+ auto BuildHeaderHolders (HeaderViews headers, std::size_t count) {
88+ std::vector<impl::HeadersHolder> holders;
89+ holders.reserve (count);
90+ for (std::size_t i = 0 ; i < count; ++i) holders.emplace_back (impl::HeadersHolder{headers});
91+ return holders;
92+ }
93+
94+ void HandleDeliveryErrors (const std::vector<impl::DeliveryResult>& delivery_results) {
95+ std::map<std::size_t , std::exception_ptr> exceptions;
96+ for (std::size_t i = 0 ; i < delivery_results.size (); ++i) {
97+ const auto & delivery_result = delivery_results[i];
98+ if (!delivery_result.IsSuccess ()) {
99+ exceptions[i] = BuildSendError (delivery_result);
100+ }
74101 }
75102
76- UASSERT ( false ) ;
103+ if (!exceptions. empty ()) throw BulkSendException{ std::move (exceptions)} ;
77104}
78105
79106} // namespace
@@ -111,6 +138,22 @@ void Producer::Send(
111138 }).Get ();
112139}
113140
141+ void Producer::Send (
142+ utils::zstring_view topic_name,
143+ std::string_view key,
144+ utils::span<const std::string> messages,
145+ std::optional<std::uint32_t > partition,
146+ HeaderViews headers
147+ ) const {
148+ utils::Async (
149+ producer_task_processor_,
150+ " producer_send_bulk" ,
151+ [this , topic_name, key, messages, partition, &headers] {
152+ SendImpl (topic_name, key, messages, partition, BuildHeaderHolders (headers, messages.size ()));
153+ }
154+ ).Get ();
155+ }
156+
114157engine::TaskWithResult<void > Producer::SendAsync (
115158 std::string topic_name,
116159 std::string key,
@@ -148,8 +191,7 @@ void Producer::SendImpl(
148191
149192 std::vector<OwningHeader> headers_copy;
150193 if (testsuite::AreTestpointsAvailable ()) {
151- auto reader = HeadersReader{headers_holder.GetHandle ()};
152- headers_copy = std::vector<OwningHeader>{reader.begin (), reader.end ()};
194+ headers_copy = BuildOwningHeaders (headers_holder);
153195 }
154196 if (testsuite::AreTestpointsAvailable ()) {
155197 SendToTestPoint (name_, topic_name, key, message, partition, headers_copy, " ::started" );
@@ -166,6 +208,40 @@ void Producer::SendImpl(
166208 }
167209}
168210
211+ void Producer::SendImpl (
212+ utils::zstring_view topic_name,
213+ std::string_view key,
214+ utils::span<const std::string> messages,
215+ std::optional<std::uint32_t > partition,
216+ std::vector<impl::HeadersHolder>&& headers_holders
217+ ) const {
218+ tracing::Span::CurrentSpan ().AddTag (" kafka_producer" , name_);
219+ tracing::Span::CurrentSpan ().AddTag (" kafka_send_key" , std::string{key});
220+
221+ std::vector<std::vector<OwningHeader>> headers_copies;
222+ if (testsuite::AreTestpointsAvailable ()) {
223+ for (std::size_t i = 0 ; i < messages.size (); ++i) {
224+ headers_copies.emplace_back (BuildOwningHeaders (headers_holders[i]));
225+ }
226+ }
227+ if (testsuite::AreTestpointsAvailable ()) {
228+ for (std::size_t i = 0 ; i < messages.size (); ++i) {
229+ SendToTestPoint (name_, topic_name, key, messages[i], partition, headers_copies[i], " ::started" );
230+ }
231+ }
232+
233+ const std::vector<impl::DeliveryResult> delivery_results =
234+ producer_->Send (topic_name, key, messages, partition, std::move (headers_holders));
235+
236+ HandleDeliveryErrors (delivery_results);
237+
238+ if (testsuite::AreTestpointsAvailable ()) {
239+ for (std::size_t i = 0 ; i < messages.size (); ++i) {
240+ SendToTestPoint (name_, topic_name, key, messages[i], partition, headers_copies[i]);
241+ }
242+ }
243+ }
244+
169245} // namespace kafka
170246
171247USERVER_NAMESPACE_END
0 commit comments