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

View File

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

View File

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

View File

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

View File

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

View File

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