31
31
#define CPPKAFKA_BUFFERED_PRODUCER_H
32
32
33
33
#include < string>
34
- #include < list >
34
+ #include < deque >
35
35
#include < cstdint>
36
36
#include < algorithm>
37
37
#include < unordered_set>
@@ -52,15 +52,23 @@ namespace cppkafka {
52
52
* to produce them just as you would using the Producer class.
53
53
*
54
54
* When calling either flush or wait_for_acks, the buffered producer will block until all
55
- * produced messages (either in a buffer or non buffered way) are acknowledged by the kafka
56
- * brokers.
55
+ * produced messages (either buffered or sent directly) are acknowledged by the kafka brokers.
57
56
*
58
57
* When producing messages, this class will handle cases where the producer's queue is full so it
59
58
* will poll until the production is successful.
60
59
*
61
60
* \remark This class is thread safe
62
61
*
63
- * \warning The application *MUST NOT* change the payload policy on the underlying Producer object.
62
+ * \warning
63
+ * Delivery Report Callback: This class makes internal use of this function and will overwrite anything
64
+ * the user has supplied as part of the configuration options. Instead user should call
65
+ * set_produce_success_callback() and set_produce_failure_callback() respectively.
66
+ *
67
+ * Payload Policy: For payload-owning BufferTypes such as std::string or std::vector<char> the default
68
+ * policy is set to Producer::PayloadPolicy::COPY_PAYLOAD. For the specific non-payload owning type
69
+ * cppkafka::Buffer the policy is Producer::PayloadPolicy::PASSTHROUGH_PAYLOAD. In this case, librdkafka
70
+ * shall not make any internal copies of the message and it is the application's responsability to free
71
+ * the messages *after* the delivery report callback has reported a successful delivery to avoid corruption.
64
72
*/
65
73
template <typename BufferType>
66
74
class CPPKAFKA_API BufferedProducer {
@@ -69,6 +77,11 @@ class CPPKAFKA_API BufferedProducer {
69
77
* Concrete builder
70
78
*/
71
79
using Builder = ConcreteMessageBuilder<BufferType>;
80
+
81
+ /* *
82
+ * Callback to indicate a message was delivered to the broker
83
+ */
84
+ using ProduceSuccessCallback = std::function<void (const Message&)>;
72
85
73
86
/* *
74
87
* Callback to indicate a message failed to be produced by the broker
@@ -137,6 +150,10 @@ class CPPKAFKA_API BufferedProducer {
137
150
*
138
151
* This will send all messages and keep waiting until all of them are acknowledged (this is
139
152
* done by calling wait_for_acks).
153
+ *
154
+ * \remark Although it is possible to call flush from multiple threads concurrently, better
155
+ * performance is achieved when called from the same thread or when serialized wrt
156
+ * to other threads.
140
157
*/
141
158
void flush ();
142
159
@@ -216,6 +233,15 @@ class CPPKAFKA_API BufferedProducer {
216
233
*/
217
234
void set_produce_failure_callback (ProduceFailureCallback callback);
218
235
236
+ /* *
237
+ * \brief Sets the successful delivery callback
238
+ *
239
+ * The user can use this function to cleanup any application-owned message buffers.
240
+ *
241
+ * \param callback The callback to be set
242
+ */
243
+ void set_produce_success_callback (ProduceSuccessCallback callback);
244
+
219
245
/* *
220
246
* \brief Sets the local message produce failure callback
221
247
*
@@ -231,7 +257,7 @@ class CPPKAFKA_API BufferedProducer {
231
257
void set_flush_failure_callback (FlushFailureCallback callback);
232
258
233
259
private:
234
- using QueueType = std::list <Builder>;
260
+ using QueueType = std::deque <Builder>;
235
261
enum class MessagePriority { Low, High };
236
262
237
263
template <typename BuilderType>
@@ -242,23 +268,31 @@ class CPPKAFKA_API BufferedProducer {
242
268
void on_delivery_report (const Message& message);
243
269
244
270
// Members
245
- Configuration::DeliveryReportCallback delivery_report_callback_;
246
271
Producer producer_;
247
272
QueueType messages_;
248
273
mutable std::mutex mutex_;
274
+ ProduceSuccessCallback produce_success_callback_;
249
275
ProduceFailureCallback produce_failure_callback_;
250
276
FlushFailureCallback flush_failure_callback_;
251
277
ssize_t max_buffer_size_{-1 };
252
278
std::atomic_ulong expected_acks_{0 };
253
279
std::atomic_ullong total_messages_acked_{0 };
254
280
};
255
281
282
+ template <typename BufferType>
283
+ Producer::PayloadPolicy get_default_payload_policy () {
284
+ return Producer::PayloadPolicy::COPY_PAYLOAD;
285
+ }
286
+
287
+ template <> inline
288
+ Producer::PayloadPolicy get_default_payload_policy<Buffer>() {
289
+ return Producer::PayloadPolicy::PASSTHROUGH_PAYLOAD;
290
+ }
291
+
256
292
template <typename BufferType>
257
293
BufferedProducer<BufferType>::BufferedProducer(Configuration config)
258
- : delivery_report_callback_(config.get_delivery_report_callback()),
259
- producer_ (prepare_configuration(std::move(config))) {
260
- // Allow re-queuing failed messages
261
- producer_.set_payload_policy (Producer::PayloadPolicy::PASSTHROUGH_PAYLOAD);
294
+ : producer_(prepare_configuration(std::move(config))) {
295
+ producer_.set_payload_policy (get_default_payload_policy<BufferType>());
262
296
}
263
297
264
298
template <typename BufferType>
@@ -392,6 +426,11 @@ void BufferedProducer<BufferType>::set_produce_failure_callback(ProduceFailureCa
392
426
produce_failure_callback_ = std::move (callback);
393
427
}
394
428
429
+ template <typename BufferType>
430
+ void BufferedProducer<BufferType>::set_produce_success_callback(ProduceSuccessCallback callback) {
431
+ produce_success_callback_ = std::move (callback);
432
+ }
433
+
395
434
template <typename BufferType>
396
435
void BufferedProducer<BufferType>::set_flush_failure_callback(FlushFailureCallback callback) {
397
436
flush_failure_callback_ = std::move (callback);
@@ -433,11 +472,6 @@ void BufferedProducer<BufferType>::on_delivery_report(const Message& message) {
433
472
--expected_acks_;
434
473
assert (expected_acks_ != (unsigned long )-1 ); // Prevent underflow
435
474
436
- // Call the user-supplied delivery report callback if any
437
- if (delivery_report_callback_) {
438
- delivery_report_callback_ (producer_, message);
439
- }
440
-
441
475
// We should produce this message again if it has an error and we either don't have a
442
476
// produce failure callback or we have one but it returns true
443
477
bool should_produce = message.get_error () &&
@@ -447,6 +481,10 @@ void BufferedProducer<BufferType>::on_delivery_report(const Message& message) {
447
481
do_add_message (Builder (message), MessagePriority::High, false );
448
482
}
449
483
else {
484
+ // Successful delivery
485
+ if (produce_success_callback_) {
486
+ produce_success_callback_ (message);
487
+ }
450
488
// Increment the total successful transmissions
451
489
++total_messages_acked_;
452
490
}
0 commit comments