From 2d080f14eb8e02006f75d579f9500a2a7f60e163 Mon Sep 17 00:00:00 2001 From: Julian Brost Date: Tue, 19 Jan 2021 10:56:54 +0100 Subject: [PATCH] IcingaDB: start initial dump in callback instead of timer Previously, the initial config dump was started in a timer executed every 15 seconds. During the first execution of the timer, the Redis connection is typically not established yet. Therefore, this delayed the initial sync by up to 15 seconds. This commit instead triggers the sync from a callback that is executed after the connection is successfully established. The timer is removed completely. On first glance, it looks like it would ensure that a lost connection is reestablished, but this is handled internally by RedisConnection. After the config has been dumped once, that timer wouldn't ever attempt a reconnect anyways. --- lib/icingadb/icingadb-objects.cpp | 1 + lib/icingadb/icingadb.cpp | 28 ++++++---------------------- lib/icingadb/icingadb.hpp | 4 +--- lib/icingadb/redisconnection.cpp | 15 +++++++++++++++ lib/icingadb/redisconnection.hpp | 4 ++++ 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/lib/icingadb/icingadb-objects.cpp b/lib/icingadb/icingadb-objects.cpp index c541a7552..db4ab6ab8 100644 --- a/lib/icingadb/icingadb-objects.cpp +++ b/lib/icingadb/icingadb-objects.cpp @@ -117,6 +117,7 @@ void IcingaDB::ConfigStaticInitialize() void IcingaDB::UpdateAllConfigObjects() { + Log(LogInformation, "IcingaDB") << "Starting initial config/status dump"; double startTime = Utility::GetTime(); // Use a Workqueue to pack objects in parallel diff --git a/lib/icingadb/icingadb.cpp b/lib/icingadb/icingadb.cpp index 8e3de34d9..3b90d42e8 100644 --- a/lib/icingadb/icingadb.cpp +++ b/lib/icingadb/icingadb.cpp @@ -63,16 +63,13 @@ void IcingaDB::Start(bool runtimeCreated) m_ConfigDumpInProgress = false; m_ConfigDumpDone = false; - m_Rcon = new RedisConnection(GetHost(), GetPort(), GetPath(), GetPassword(), GetDbIndex()); - m_Rcon->Start(); - m_WorkQueue.SetExceptionCallback([this](boost::exception_ptr exp) { ExceptionHandler(std::move(exp)); }); - m_ReconnectTimer = new Timer(); - m_ReconnectTimer->SetInterval(15); - m_ReconnectTimer->OnTimerExpired.connect([this](const Timer * const&) { ReconnectTimerHandler(); }); - m_ReconnectTimer->Start(); - m_ReconnectTimer->Reschedule(0); + m_Rcon = new RedisConnection(GetHost(), GetPort(), GetPath(), GetPassword(), GetDbIndex()); + m_Rcon->SetConnectedCallback([this](boost::asio::yield_context& yc) { + m_WorkQueue.Enqueue([this]() { OnConnectedHandler(); }); + }); + m_Rcon->Start(); m_StatsTimer = new Timer(); m_StatsTimer->SetInterval(1); @@ -93,23 +90,10 @@ void IcingaDB::ExceptionHandler(boost::exception_ptr exp) << "Exception during redis operation: " << DiagnosticInformation(exp); } -void IcingaDB::ReconnectTimerHandler() -{ - m_WorkQueue.Enqueue([this]() { TryToReconnect(); }); -} - -void IcingaDB::TryToReconnect() +void IcingaDB::OnConnectedHandler() { AssertOnWorkQueue(); - if (m_ConfigDumpDone) - return; - else - m_Rcon->Start(); - - if (!m_Rcon || !m_Rcon->IsConnected()) - return; - if (m_ConfigDumpInProgress || m_ConfigDumpDone) return; diff --git a/lib/icingadb/icingadb.hpp b/lib/icingadb/icingadb.hpp index 41fd0963c..b7edb6f0c 100644 --- a/lib/icingadb/icingadb.hpp +++ b/lib/icingadb/icingadb.hpp @@ -35,8 +35,7 @@ public: virtual void Stop(bool runtimeRemoved) override; private: - void ReconnectTimerHandler(); - void TryToReconnect(); + void OnConnectedHandler(); void PublishStatsTimerHandler(); void PublishStats(); @@ -134,7 +133,6 @@ private: } Timer::Ptr m_StatsTimer; - Timer::Ptr m_ReconnectTimer; WorkQueue m_WorkQueue; String m_PrefixConfigObject; diff --git a/lib/icingadb/redisconnection.cpp b/lib/icingadb/redisconnection.cpp index 94db408d5..9a75885c1 100644 --- a/lib/icingadb/redisconnection.cpp +++ b/lib/icingadb/redisconnection.cpp @@ -233,6 +233,10 @@ void RedisConnection::Connect(asio::yield_context& yc) Log(LogInformation, "IcingaDB", "Connected to Redis server"); + if (m_ConnectedCallback) { + m_ConnectedCallback(yc); + } + break; } catch (const boost::coroutines::detail::forced_unwind&) { throw; @@ -500,3 +504,14 @@ void RedisConnection::WriteOne(RedisConnection::Query& query, asio::yield_contex WriteOne(m_UnixConn, query, yc); } } + +/** + * Specify a callback that is run each time a connection is successfully established + * + * The callback is executed from a Boost.Asio coroutine and should therefore not perform blocking operations. + * + * @param callback Callback to execute + */ +void RedisConnection::SetConnectedCallback(std::function callback) { + m_ConnectedCallback = std::move(callback); +} diff --git a/lib/icingadb/redisconnection.hpp b/lib/icingadb/redisconnection.hpp index 222e99cb3..71777e22e 100644 --- a/lib/icingadb/redisconnection.hpp +++ b/lib/icingadb/redisconnection.hpp @@ -82,6 +82,8 @@ namespace icinga void SuppressQueryKind(QueryPriority kind); void UnsuppressQueryKind(QueryPriority kind); + void SetConnectedCallback(std::function callback); + private: /** * What to do with the responses to Redis queries. @@ -179,6 +181,8 @@ namespace icinga // Indicate that there's something to send/receive AsioConditionVariable m_QueuedWrites, m_QueuedReads; + + std::function m_ConnectedCallback; }; /**