-
Notifications
You must be signed in to change notification settings - Fork 0
Timers and Watchdog
SERP provides two time-based primitives:
-
serp::Timer— schedule a callback to run after a delay, or repeatedly on an interval. -
serp::Watchdog— enforce a hard timeout on an operation; if the watchdog fires before being reset, the process aborts.
Both primitives are bound to an EventLoop. Their callbacks fire on that loop's thread, making them safe to use alongside service-owned state without additional locking.
static std::shared_ptr<serp::Timer> serp::Timer::create(
serp::EventLoop& loop,
std::chrono::duration<...> interval,
std::function<void()> callback
);| Parameter | Description |
|---|---|
loop |
The EventLoop the callback fires on. Typically eventLoop() inside a service. |
interval |
Time between firings (for repeating timers) or delay before the single firing. |
callback |
The function to call when the timer fires. |
| Method | Description |
|---|---|
start() |
Arm the timer. For repeating timers, the first fire occurs after interval. |
stop() |
Disarm the timer. The callback will not fire again until start() is called. |
restart() |
Reset the interval and re-arm. Equivalent to stop() + start(). |
By default, timers are repeating — they fire every interval until stopped.
To create a one-shot timer, set the isRepeating flag:
auto timer = serp::Timer::create(loop, std::chrono::milliseconds(500), callback);
timer->setRepeating(false);
timer->start();
// Fires once after 500ms, then stops automaticallyclass SensorService : public SensorServiceBase {
protected:
void onInitialize() override {
m_pollTimer = serp::Timer::create(
eventLoop(),
std::chrono::seconds(1),
[this]() { pollStatus(); }
);
m_pollTimer->start();
}
void onDeinitialize() override {
m_pollTimer->stop();
}
private:
void pollStatus() {
// Runs on SensorService's EventLoop every second
double reading = m_sensor.read();
temperature.mutate(reading);
}
std::shared_ptr<serp::Timer> m_pollTimer;
};auto delay = serp::Timer::create(eventLoop(), std::chrono::seconds(3), [this]() {
applyDeferredSettings();
});
delay->setRepeating(false);
delay->start();Timers are reference-counted via shared_ptr. The timer is automatically stopped and destroyed when the last reference is released. Store the shared_ptr as a member to keep the timer alive:
std::shared_ptr<serp::Timer> m_timer;Dropping the shared_ptr in onDeinitialize() is safe and will stop the timer.
A watchdog enforces a hard deadline on an operation. If reset() is not called before the timeout expires, the watchdog fires and aborts the process. This makes watchdogs suitable for safety-critical enforcement — they cannot be silently skipped.
static std::shared_ptr<serp::Watchdog> serp::Watchdog::create(
serp::EventLoop& loop,
std::chrono::duration<...> timeout
);| Method | Description |
|---|---|
start() |
Arm the watchdog. The countdown begins. |
reset() |
Restart the countdown. Call this periodically to confirm liveness. |
stop() |
Disarm the watchdog. The timeout is cancelled. |
If the watchdog fires (timeout expires before reset() or stop() is called), the process terminates. This is intentional — a hung service should not silently block the system.
class UpdaterService : public UpdaterServiceBase {
void performUpdate() {
auto wd = serp::Watchdog::create(eventLoop(), std::chrono::seconds(5));
wd->start();
doLongOperation(); // Must complete in under 5 seconds
wd->reset(); // Confirm completion; restarts countdown
// or:
wd->stop(); // Disarm entirely when done
}
};For long-running loops where individual steps are bounded but the overall loop must keep progressing:
void processLoop() {
auto wd = serp::Watchdog::create(eventLoop(), std::chrono::seconds(10));
wd->start();
while (!m_done) {
processNextItem();
wd->reset(); // Must be called at least once every 10 seconds
}
wd->stop();
}The Serp::command library's CommandProcessor uses serp::Watchdog internally: each command dispatched through the processor has an associated watchdog. If a command handler does not complete within the configured timeout, the processor aborts. This behavior is automatic and requires no manual watchdog setup in command handlers.
| Scenario | Use |
|---|---|
| Periodic task (polling, heartbeat send) |
serp::Timer (repeating) |
| Delayed one-shot action |
serp::Timer (one-shot) |
| Enforcing a deadline — abort on timeout | serp::Watchdog |
| Detecting a hung service | serp::Watchdog |
| Async operation timeout with graceful fallback |
serp::Timer + serp::Promise::reject()
|
- Services and Lifecycle — EventLoop and thread model
- Promises and Async — combining timers with async operations for graceful timeouts
Getting Started
The Development Model
Architecture Language
Code Generator
- Generator Overview
- Generated Code Layout
- Deployment Configurations
- Lifecycle Backends
- CMake Integration
Framework Internals
- Core Concepts
- Services & Lifecycle
- Methods
- Properties
- Notifications
- Timers & Watchdog
- Promises & Async
- Streams
- Commands
- Logging
- Test Engine
- Transports
- Runtime & Debug Tools
VS Code Plugin
Examples