107 std::atomic<bool> accepting_items {
true};
108 std::atomic<bool> shutdown_initiated {
false};
109 std::once_flag shutdown_invoked;
113 static constexpr std::chrono::milliseconds DEFAULT_SHUTDOWN_DRAIN_MS {1000};
135#if defined(DEBUG) || defined(_DEBUG)
136 std::cerr << std::format(
"{} - Waiting for queue to be empty: {}\n", __func__, items.toJson().dump(2));
142 bool shutdown(std::chrono::milliseconds timeout = DEFAULT_SHUTDOWN_DRAIN_MS)
144 bool shutdown_status {
false};
148 [&](
bool& status, std::chrono::milliseconds& t) {
149 accepting_items.store(
false, std::memory_order_release);
151 std::cerr << std::format(
"worker shutdown started inside call_once.. asking for waitUntilEmpty...for {}ms\n", t.count());
156 auto deadline = std::chrono::steady_clock::now() + t + std::chrono::milliseconds(500);
157 auto isDrained = items.waitUntilEmpty(t);
160 std::cerr << std::format(
"worker shutdown possible; isDrained: {}. size:{}\n", isDrained, items.size());
164 processor.request_stop();
166 std::cerr << std::format(
"worker shutdown started inside call_once\n");
169 if (processor.joinable()) {
173 std::cerr << std::format(
"worker shutdown ok; isDrained: {}. size:{}\n", isDrained, items.size());
178 std::cerr << std::format(
"worker shutdown failed; isDrained: {}. size:{}\n", isDrained, items.size());
181 std::cerr <<
"WARNING: Graceful shutdown timeout exceeded\n";
188 return shutdown_status;
235 void queue(T&& item)
noexcept(
false)
237 if (!accepting_items.load(std::memory_order_acquire)) {
238 throw std::runtime_error(
"Worker is shutting down, cannot queue new items");
241 items.emplace(std::move(item));
242 queueCounter.fetch_add(1, std::memory_order_release);
245#if defined(NLOHMANN_JSON_VERSION_MAJOR)
267 auto toJson() const -> nlohmann::json
269 auto itemsSize = items.size();
270 auto itemsQueued = items.addCounter();
271 auto itemsPopped = items.removeCounter();
272 auto itemsOutstanding = itemsQueued - itemsPopped;
274 return {{
"_typver",
"siddiqsoft.asynchrony-lib.simple_worker/0.10"},
275 {
"itemsSize", itemsSize},
276 {
"queueCounter", queueCounter.load(std::memory_order_acquire)},
277 {
"itemsQueued", itemsQueued},
278 {
"itemsPopped", itemsPopped},
279 {
"itemsOutstanding", itemsOutstanding},
280 {
"threadPriority", Pri},
281 {
"outstandingCallback", outstandingCallback.load(std::memory_order_acquire)},
288 std::once_flag flag_forceCleanupTerminate {};
292 std::atomic_uint outstandingCallback {0};
295 std::atomic_uint64_t queueCounter {0};
298 siddiqsoft::WaitableQueue<T> items {};
301 std::function<void(T&&)> callback;
319 std::jthread processor {[&](std::stop_token st) {
320#if defined(WIN64) || defined(_WIN64) || defined(WIN32) || defined(_WIN32)
322 if constexpr (Pri != 0) SetThreadPriority(GetCurrentThread(), Pri);
325 while (!st.stop_requested()) {
335 callback(std::move(*item));
337 catch (
const std::exception& ex) {
339 std::cerr << std::format(
"Ignoring Exception in simple_worker callback: {} - inner\n", ex.what());
343 catch (
const std::exception& ex) {
345 std::cerr << std::format(
"Ignoring Exception in simple_worker callback: {} - outer\n", ex.what());
349 std::cerr << std::format(
"WARNING: Abandon {} items processing due to stop request!\n", items.size());
366 static void to_json(nlohmann::json& dest,
const siddiqsoft::simple_worker<T, Pri>& src)