Replaced termination callback with throwing exception

This commit is contained in:
Alexander Damian
2019-04-24 10:30:32 -04:00
parent e8c4397b66
commit 0c1119727b
6 changed files with 73 additions and 34 deletions

View File

@@ -7,20 +7,17 @@ set(CPPKAFKA_VERSION_MINOR 2)
set(CPPKAFKA_VERSION "${CPPKAFKA_VERSION_MAJOR}.${CPPKAFKA_VERSION_MINOR}")
set(RDKAFKA_MIN_VERSION 0x00090400)
if (NOT CMAKE_CXX_FLAGS)
# Set default compile flags for the project
if(MSVC)
if(MSVC)
# Don't always use Wall, since VC's /Wall is ridiculously verbose.
set(CMAKE_CXX_FLAGS "/W3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3")
# Disable VC secure checks, since these are not really issues
add_definitions("-D_CRT_SECURE_NO_WARNINGS=1")
add_definitions("-D_SCL_SECURE_NO_WARNINGS=1")
add_definitions("-DNOGDI=1")
add_definitions("-DNOMINMAX=1")
else()
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall")
endif()
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")

View File

@@ -42,6 +42,10 @@ namespace cppkafka {
*/
class CPPKAFKA_API Error {
public:
/**
* @brief Constructs an error object with RD_KAFKA_RESP_ERR_NO_ERROR
*/
Error() = default;
/**
* Constructs an error object
*/
@@ -77,7 +81,7 @@ public:
*/
CPPKAFKA_API friend std::ostream& operator<<(std::ostream& output, const Error& rhs);
private:
rd_kafka_resp_err_t error_;
rd_kafka_resp_err_t error_{RD_KAFKA_RESP_ERR_NO_ERROR};
};
} // cppkafka

View File

@@ -100,10 +100,18 @@ public:
*/
void set_error_callback(ErrorCallback callback);
/**
* \brief Commits the current partition assignment synchronously
*
* This will call Consumer::commit() until either the message is successfully
* committed or the error callback returns false (if any is set).
*/
void commit();
/**
* \brief Commits the given message synchronously
*
* This will call Consumer::commit until either the message is successfully
* This will call Consumer::commit(msg) until either the message is successfully
* committed or the error callback returns false (if any is set).
*
* \param msg The message to be committed
@@ -113,7 +121,7 @@ public:
/**
* \brief Commits the offsets on the given topic/partitions synchronously
*
* This will call Consumer::commit until either the offsets are successfully
* This will call Consumer::commit(topic_partitions) until either the offsets are successfully
* committed or the error callback returns false (if any is set).
*
* \param topic_partitions The topic/partition list to be committed
@@ -127,26 +135,35 @@ public:
*/
Consumer& get_consumer();
private:
// Return true to abort and false to continue committing
// If the ReturnType contains 'true', we abort committing. Otherwise we continue.
// The second member of the ReturnType contains the RdKafka error if any.
template <typename T>
bool do_commit(const T& object) {
ReturnType do_commit(const T* object) {
ReturnType rt;
try {
consumer_.commit(object);
// If the commit succeeds, we're done
return true;
if (!object) {
consumer_.commit();
}
else {
consumer_.commit(*object);
}
// If the commit succeeds, we're done.
}
catch (const HandleException& ex) {
rt.error_ = ex.get_error();
// If there were actually no offsets to commit, return. Retrying won't solve
// anything here
if (ex.get_error() == RD_KAFKA_RESP_ERR__NO_OFFSET) {
return true;
}
// If there's a callback and it returns false for this message, abort.
// Otherwise keep committing.
if (rt.error_ != RD_KAFKA_RESP_ERR__NO_OFFSET) {
// If there's no callback or if returns true for this message, keep committing.
// Otherwise abort.
CallbackInvoker<ErrorCallback> callback("backoff committer", callback_, &consumer_);
return callback && !callback(ex.get_error());
if (!callback || callback(rt.error_)) {
rt.abort_ = false; //continue retrying
}
}
}
return rt;
}
Consumer& consumer_;
ErrorCallback callback_;

View File

@@ -34,6 +34,7 @@
#include <functional>
#include <thread>
#include "../consumer.h"
#include "../exceptions.h"
namespace cppkafka {
@@ -48,6 +49,14 @@ public:
static const TimeUnit DEFAULT_MAXIMUM_BACKOFF;
static const size_t DEFAULT_MAXIMUM_RETRIES;
/**
* @brief Type which any functor must return.
*/
struct ReturnType {
bool abort_{true};
Error error_;
};
/**
* The backoff policy to use
*/
@@ -119,11 +128,16 @@ public:
void perform(const Functor& callback) {
TimeUnit backoff = initial_backoff_;
size_t retries = maximum_retries_;
ReturnType rt;
while (retries--) {
auto start = std::chrono::steady_clock::now();
// If the callback returns true, we're done
if (callback()) {
return;
rt = callback();
if (rt.abort_) {
if (rt.error_) {
break; //terminal error
}
return; //success
}
auto end = std::chrono::steady_clock::now();
auto time_elapsed = end - start;
@@ -134,6 +148,8 @@ public:
// Increase out backoff depending on the policy being used
backoff = increase_backoff(backoff);
}
// No more retries left or we have a terminal error.
throw ConsumerException(rt.error_);
}
private:
TimeUnit increase_backoff(TimeUnit backoff);

View File

@@ -38,7 +38,6 @@ using std::vector;
using std::set;
using std::ostream;
using std::string;
using std::equal;
namespace cppkafka {

View File

@@ -43,15 +43,21 @@ void BackoffCommitter::set_error_callback(ErrorCallback callback) {
callback_ = move(callback);
}
void BackoffCommitter::commit() {
perform([&]()->ReturnType {
return do_commit<TopicPartitionList>(nullptr);
});
}
void BackoffCommitter::commit(const Message& msg) {
perform([&] {
return do_commit(msg);
perform([&]()->ReturnType {
return do_commit(&msg);
});
}
void BackoffCommitter::commit(const TopicPartitionList& topic_partitions) {
perform([&] {
return do_commit(topic_partitions);
perform([&]()->ReturnType {
return do_commit(&topic_partitions);
});
}