# How to Use periodic_worker for Scheduled Tasks in spdlog

> Learn how to use periodic_worker in spdlog to schedule tasks. This RAII helper runs callbacks on a dedicated thread at fixed intervals, automatically managing thread lifecycles. Optimize your C++ logging.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-07-14

---

**`spdlog::details::periodic_worker`** is an RAII-style helper that runs a user-provided callback on a dedicated thread at fixed intervals, automatically managing thread lifecycle through a condition variable and mutex.

The spdlog logging library provides a lightweight concurrency primitive called `periodic_worker` for executing background tasks on a schedule. Located in the `include/spdlog/details/` directory, this header-only component allows you to embed periodic execution logic directly into sinks or custom classes without manually managing thread lifecycle.

## Understanding periodic_worker Design

### RAII Thread Management

According to the source code in [`include/spdlog/details/periodic_worker.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/periodic_worker.h), the class encapsulates a `std::thread` that remains suspended until the interval elapses. The constructor accepts a `std::function<void()>` callback and a `std::chrono::duration` interval. If the interval is greater than zero, the class immediately spawns a thread that loops indefinitely.

### Condition Variable and Shutdown

The implementation in [`include/spdlog/details/periodic_worker-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/periodic_worker-inl.h) reveals that the worker uses a `std::condition_variable` named `cv_` to block the thread. Inside the loop, `cv_.wait_for` pauses execution for the specified duration unless the `active_` flag is cleared. When the destructor runs, it acquires the mutex, sets `active_` to `false`, notifies the condition variable to break the wait, and joins the thread, ensuring clean shutdown without leaking resources.

## Basic Usage Example

To create a simple timer that prints a message every second, instantiate `spdlog::details::periodic_worker` with a lambda and a duration:

```cpp
#include <spdlog/details/periodic_worker.h>
#include <chrono>
#include <iostream>

int main() {
    // Print a message every second
    spdlog::details::periodic_worker ticker(
        []() { std::cout << "tick: " << std::chrono::system_clock::now().time_since_epoch().count() << '\n'; },
        std::chrono::seconds(1));

    // Let it run for 5 seconds
    std::this_thread::sleep_for(std::chrono::seconds(5));
    // `ticker` is destroyed here, thread stops cleanly
}

```

## Embedding periodic_worker in Custom Classes

The class is designed to be used as a member variable. This example shows how to automatically flush a logger every 30 seconds:

```cpp
#include <spdlog/details/periodic_worker.h>
#include <spdlog/spdlog.h>
#include <chrono>

class LogFlusher {
public:
    LogFlusher(std::shared_ptr<spdlog::logger> logger)
        : logger_(std::move(logger)),
          flusher_([this] { logger_->flush(); }, std::chrono::seconds(30)) {}

private:
    std::shared_ptr<spdlog::logger> logger_;
    spdlog::details::periodic_worker flusher_;   // runs logger_->flush() every 30s
};

```

## Disabling the Worker with Zero Interval

If you pass a zero-length duration to the constructor, the worker becomes inactive and does not spawn a thread. This is useful for conditional periodic behavior:

```cpp
spdlog::details::periodic_worker disabled_worker(
    [](){ /* never called */ },
    std::chrono::seconds(0));   // worker becomes inactive, no thread is started

```

## Implementation Details

The header-only design means that when `SPDLOG_HEADER_ONLY` is defined, the implementation from [`include/spdlog/details/periodic_worker-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/periodic_worker-inl.h) is inlined directly into your translation unit. The worker stores the callback as a `std::function<void()>` and the interval as a `std::chrono::duration`, making it compatible with any time unit from milliseconds to hours.

## Summary

- **`spdlog::details::periodic_worker`** provides RAII-style periodic task execution in a header-only format.
- The constructor accepts a `std::function<void()>` and a `std::chrono::duration`; passing a zero duration disables the worker.
- The destructor safely stops the thread by clearing the `active_` flag, notifying the condition variable, and joining the thread.
- You can embed it as a member variable in sinks or utility classes to automatically run background tasks like log flushing or heartbeat messages.

## Frequently Asked Questions

### What happens if I pass a zero interval to periodic_worker?

When the interval is zero, the constructor sets the worker to inactive and does not spawn any thread. The callback is never invoked, and the destructor performs no thread operations, making it safe to use as a no-op placeholder.

### Is periodic_worker thread-safe?

The class itself is thread-safe for construction and destruction from the owning thread. However, the callback function you provide must handle its own synchronization if it accesses shared data. The internal mutex and condition variable protect only the `active_` state and thread lifecycle, not the contents of your callback.

### How do I stop the periodic_worker manually?

There is no public `stop()` method. The worker follows strict RAII semantics and only stops when the object is destroyed. To temporarily pause execution, you must destroy the `periodic_worker` instance and recreate it later, or implement a custom active flag inside your callback logic.

### Can I change the interval after construction?

No, the interval is fixed at construction time. To modify the timing, you must destroy the existing `periodic_worker` and create a new one with the desired interval. This design keeps the implementation minimal and lock-free for the common case.