From 2a7fd37e937aa4a5d1ea8a76ab17897f1c4ca917 Mon Sep 17 00:00:00 2001 From: Baber Nawaz Date: Wed, 8 Oct 2025 20:57:30 +0100 Subject: [PATCH] feat: Add ThrottledInvoker utility Common use case is throttling logging. SDB-9889 --- toolbox/sys/Time.hpp | 21 +++++++++++++++++++++ toolbox/sys/Time.ut.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/toolbox/sys/Time.hpp b/toolbox/sys/Time.hpp index b3f565656..e677b300c 100644 --- a/toolbox/sys/Time.hpp +++ b/toolbox/sys/Time.hpp @@ -468,6 +468,27 @@ struct TypeTraits { } }; +/// Throttles the invocation of a callable to not exceed a specified rate. +/// The rate is controlled by a cooldown interval. +class ThrottledInvoker { + public: + explicit ThrottledInvoker(Seconds cooldown_interval) + : cooldown_interval_(cooldown_interval) {} + + template + void operator()(MonoTime now, Callable&& callable) + { + if (duration_cast(now - last_time_invoked_) >= cooldown_interval_) { + last_time_invoked_ = now; + std::forward(callable)(); + } + } + + private: + const Seconds cooldown_interval_{}; + MonoTime last_time_invoked_{}; +}; + } // namespace util } // namespace toolbox diff --git a/toolbox/sys/Time.ut.cpp b/toolbox/sys/Time.ut.cpp index 72d6fb095..63d176702 100644 --- a/toolbox/sys/Time.ut.cpp +++ b/toolbox/sys/Time.ut.cpp @@ -124,4 +124,36 @@ BOOST_AUTO_TEST_CASE(PutTimeOutput2) BOOST_CHECK_EQUAL(stream.str(), "20180824T05:32:29.001001001"); } +BOOST_AUTO_TEST_CASE(ThrottledInvokerCheck) +{ + constexpr auto threshold = 1s; + ThrottledInvoker throttler{threshold}; + + std::size_t count = 0; + auto fn = [&]() { ++count; }; + auto now = MonoClock::now(); + + // First time, so throttler will invoke the callable. + // After this, the throttler should throttle until now + threshold. + throttler(now, fn); + BOOST_CHECK_EQUAL(count, 1); + + now += Millis{500}; + throttler(now, fn); + BOOST_CHECK_EQUAL(count, 1); + + now += Millis{500}; + throttler(now, fn); + BOOST_CHECK_EQUAL(count, 2); + + now += Millis{500}; + throttler(now, fn); + BOOST_CHECK_EQUAL(count, 2); + + now += Millis{500}; + throttler(now, fn); + BOOST_CHECK_EQUAL(count, 3); +} + + BOOST_AUTO_TEST_SUITE_END()