mirror of
				https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka.git
				synced 2025-10-31 18:47:48 +00:00 
			
		
		
		
	Change internals of BufferedProducer
This commit is contained in:
		| @@ -128,6 +128,24 @@ public: | ||||
|      * \param timeout The timeout used on this call | ||||
|      */ | ||||
|     int poll(std::chrono::milliseconds timeout); | ||||
|  | ||||
|     /** | ||||
|      * \brief Flush all outstanding produce requests | ||||
|      * | ||||
|      * This translates into a call to rd_kafka_flush. | ||||
|      * | ||||
|      * The timeout used on this call is the one configured via Producer::set_timeout. | ||||
|      */ | ||||
|     void flush(); | ||||
|  | ||||
|     /** | ||||
|      * \brief Flush all outstanding produce requests | ||||
|      * | ||||
|      * This translates into a call to rd_kafka_flush | ||||
|      * | ||||
|      * \param timeout The timeout used on this call | ||||
|      */ | ||||
|     void flush(std::chrono::milliseconds timeout); | ||||
| private: | ||||
|     PayloadPolicy message_payload_policy_; | ||||
| }; | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| #define CPPKAFKA_BUFFERED_PRODUCER_H | ||||
|  | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <queue> | ||||
| #include <type_traits> | ||||
| #include <cstdint> | ||||
| #include <unordered_set> | ||||
| @@ -22,6 +22,11 @@ public: | ||||
|      */ | ||||
|     using Builder = ConcreteMessageBuilder<BufferType>; | ||||
|  | ||||
|     /** | ||||
|      * Callback to indicate a message failed to be produced. | ||||
|      */ | ||||
|     using ProduceFailureCallback = std::function<bool(const Message&)>; | ||||
|  | ||||
|     /** | ||||
|      * \brief Constructs a buffered producer using the provided configuration | ||||
|      * | ||||
| @@ -71,21 +76,32 @@ public: | ||||
|      * Simple helper to construct a builder object | ||||
|      */ | ||||
|     Builder make_builder(std::string topic); | ||||
|  | ||||
|     /** | ||||
|      * \brief Sets the message produce failure callback | ||||
|      * | ||||
|      * This will be called when the delivery report callback is executed for a message having | ||||
|      * an error. The callback should return true if the message should be re-sent, otherwise | ||||
|      * false. Note that if the callback return false, then the message will be discarded. | ||||
|      * | ||||
|      * \param callback The callback to be set | ||||
|      */ | ||||
|     void set_produce_failure_callback(ProduceFailureCallback callback); | ||||
| private: | ||||
|     // Pick the most appropriate index type depending on the platform we're using | ||||
|     using IndexType = std::conditional<sizeof(void*) == 8, uint64_t, uint32_t>::type; | ||||
|  | ||||
|     template <typename BuilderType> | ||||
|     void do_add_message(BuilderType&& builder); | ||||
|     void produce_message(IndexType index, Builder& message); | ||||
|     void produce_message(const MessageBuilder& message); | ||||
|     Configuration prepare_configuration(Configuration config); | ||||
|     void on_delivery_report(const Message& message); | ||||
|  | ||||
|     Producer producer_; | ||||
|     std::map<IndexType, Builder> messages_; | ||||
|     std::vector<IndexType> failed_indexes_; | ||||
|     IndexType current_index_{0}; | ||||
|     std::unordered_map<std::string, unsigned> topic_mapping_; | ||||
|     std::queue<Builder> messages_; | ||||
|     ProduceFailureCallback produce_failure_callback_; | ||||
|     size_t expected_acks_{0}; | ||||
|     size_t messages_acked_{0}; | ||||
| }; | ||||
|  | ||||
| template <typename BufferType> | ||||
| @@ -106,26 +122,22 @@ void BufferedProducer<BufferType>::add_message(Builder builder) { | ||||
|  | ||||
| template <typename BufferType> | ||||
| void BufferedProducer<BufferType>::flush() { | ||||
|     for (auto& message_pair : messages_) { | ||||
|         produce_message(message_pair.first, message_pair.second); | ||||
|     while (!messages_.empty()) { | ||||
|         produce_message(messages_.front()); | ||||
|         messages_.pop(); | ||||
|     } | ||||
|  | ||||
|     while (!messages_.empty()) { | ||||
|         producer_.poll(); | ||||
|         if (!failed_indexes_.empty()) { | ||||
|             for (const IndexType index : failed_indexes_) { | ||||
|                 produce_message(index, messages_.at(index)); | ||||
|             } | ||||
|         } | ||||
|         failed_indexes_.clear(); | ||||
|     messages_acked_ = 0; | ||||
|     while (messages_acked_ != expected_acks_) { | ||||
|         producer_.flush(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename BufferType> | ||||
| template <typename BuilderType> | ||||
| void BufferedProducer<BufferType>::do_add_message(BuilderType&& builder) { | ||||
|     IndexType index = messages_.size(); | ||||
|     messages_.emplace(index, std::move(builder)); | ||||
|     expected_acks_++; | ||||
|     messages_.push(std::move(builder)); | ||||
| } | ||||
|  | ||||
| template <typename BufferType> | ||||
| @@ -145,13 +157,16 @@ BufferedProducer<BufferType>::make_builder(std::string topic) { | ||||
| } | ||||
|  | ||||
| template <typename BufferType> | ||||
| void BufferedProducer<BufferType>::produce_message(IndexType index, Builder& builder) { | ||||
| void BufferedProducer<BufferType>::set_produce_failure_callback(ProduceFailureCallback callback) { | ||||
|     produce_failure_callback_ = std::move(callback); | ||||
| } | ||||
|  | ||||
| template <typename BufferType> | ||||
| void BufferedProducer<BufferType>::produce_message(const MessageBuilder& builder) { | ||||
|     bool sent = false; | ||||
|     MessageBuilder local_builder = builder; | ||||
|     local_builder.user_data(reinterpret_cast<void*>(index)); | ||||
|     while (!sent) { | ||||
|         try { | ||||
|             producer_.produce(local_builder); | ||||
|             producer_.produce(builder); | ||||
|             sent = true; | ||||
|         } | ||||
|         catch (const HandleException& ex) { | ||||
| @@ -177,19 +192,26 @@ Configuration BufferedProducer<BufferType>::prepare_configuration(Configuration | ||||
|  | ||||
| template <typename BufferType> | ||||
| void BufferedProducer<BufferType>::on_delivery_report(const Message& message) { | ||||
|     const IndexType index = reinterpret_cast<IndexType>(message.get_private_data()); | ||||
|     auto iter = messages_.find(index); | ||||
|     // Got an ACK for an unexpected message? | ||||
|     if (iter == messages_.end()) { | ||||
|     // We should produce this message again if it has an error and we either don't have a  | ||||
|     // produce failure callback or we have one but it returns true | ||||
|     bool should_produce = message.get_error() && | ||||
|                           (!produce_failure_callback_ || produce_failure_callback_(message)); | ||||
|     if (should_produce) { | ||||
|         MessageBuilder builder(message.get_topic()); | ||||
|         const auto& key = message.get_key(); | ||||
|         const auto& payload = message.get_payload(); | ||||
|         builder.partition(message.get_partition()) | ||||
|                .key(Buffer(key.get_data(), key.get_size())) | ||||
|                .payload(Buffer(payload.get_data(), payload.get_size())); | ||||
|         if (message.get_timestamp()) { | ||||
|             builder.timestamp(message.get_timestamp()->get_timestamp()); | ||||
|         } | ||||
|         produce_message(builder); | ||||
|         return; | ||||
|     } | ||||
|     // If there was an error sending this message, then we need to re-send it | ||||
|     if (message.get_error()) { | ||||
|         failed_indexes_.push_back(index); | ||||
|     } | ||||
|     else { | ||||
|         messages_.erase(iter); | ||||
|     } | ||||
|     // If production was successful or the produce failure callback returned false, then | ||||
|     // let's consider it to be acked  | ||||
|     messages_acked_++; | ||||
| } | ||||
|  | ||||
| } // cppkafka | ||||
|   | ||||
| @@ -86,4 +86,13 @@ int Producer::poll(milliseconds timeout) { | ||||
|     return rd_kafka_poll(get_handle(), timeout.count()); | ||||
| } | ||||
|  | ||||
| void Producer::flush() { | ||||
|     flush(get_timeout()); | ||||
| } | ||||
|  | ||||
| void Producer::flush(milliseconds timeout) { | ||||
|     auto result = rd_kafka_flush(get_handle(), timeout.count()); | ||||
|     check_error(result); | ||||
| } | ||||
|  | ||||
| } // cppkafka | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Matias Fontanini
					Matias Fontanini