Run checks at NSClient++ startup - #1407
Merged
Merged
Conversation
A schedule only reports for the first time once its interval (or the next matching cron time) has elapsed, so after a reboot or a configuration change the monitoring server keeps the old result for as long as the interval - hours for the checks where the status is most likely to have changed. Fixes #392. Schedules can now set `run on startup` to run the command once as soon as the agent is up, after which the normal schedule continues from that run. Setting it on the `default` schedule turns it on for every schedule which does not override it, and `startup window` spreads the startup runs out for installs with many schedules. The startup runs fire from the plugin start hook, which the core calls once every plugin is loaded - running them during module load would query commands that later modules have not registered yet. A reload gets no second start hook and is not exposed to that ordering problem, so it fires them directly. To keep a startup schedule from ending up with two independent chains of queued instances (which would make it run twice per interval forever), the scheduler learned to register a task without queueing its first run. Along the way: - Reloading the Scheduler left the tasks and queued instances from before the reload in place alongside the newly added ones, so every schedule ran twice after a reload. - A plugin loaded into an already running agent never got its start hook called, which also affected LUAScript's on-start scripts. - The schedule object's copy constructor did not copy its id, so the "Adding scheduled item" log line printed a random number. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Michael Medin <michael@medin.name>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #392.
A schedule only reports for the first time once its interval (or the next matching cron time) has elapsed, so after a reboot or a configuration change the monitoring server keeps the old result for as long as the interval — hours for exactly the checks whose status is most likely to have changed (uptime, pending updates, …).
What this adds
The command runs once as soon as the agent is up, then continues on its normal schedule from that run.
run on startupon thedefaultschedule turns it on for every schedule that does not override it (the global switch the issue asked for); an explicitrun on startup = falseon a named schedule wins.[/settings/scheduler] startup window = 30sspreads the startup runs evenly for installs with many schedules. The default (0s) runs them all immediately.How it works
Startup runs fire from the plugin start hook (
"on_start": true→Scheduler::startModule), which the core calls frompost_start_plugins()once every plugin is loaded. Firing them during module load would query commands that later-loading modules have not registered yet and submit bogusCommand was not foundUNKNOWNs. A reload never gets a second start hook and is not exposed to that ordering problem, soloadModuleExfires them directly once the module has started.The scheduler learned to register a task without queueing its first run (
add_task(..., schedule_first_run = false)+run_now). This matters: every execution queues the following one, so leaving the normal first-run instance in place next to the startup instance would make the task fire twice per interval for the lifetime of the process. Startup instances are also exempt from the "ran N seconds too late" error — they are all queued for the same instant by design — while the watchdog still sees the lag and scales the thread pool.Bugs found along the way (fixed here)
load_single_plugin, i.e. the REST module-load path) never got its start hook called. This also affected LUAScript's on-start scripts.schedule_object's copy constructor did not copyid, so the "Adding scheduled item" log line printed an indeterminate value (intervalcheck[1634497895]).Tests
schedules_handler_test.cpp— default value, template copy,to_string, and the queue-count invariants (deferred until fired, one instance per startup task, normal tasks untouched).simple_scheduler_test.cpp— deferred first run for both interval and cron tasks,run_nowincluding delay handling and unknown ids, and queue clearing.tests/scheduler-run-on-startup.test.ts— new Docker-free integration suite driving a local carbon listener through GraphiteClient. Every schedule uses a 1h interval, so any result can only have come from a startup run: explicit flag, inheritance fromdefault,run on startup = falsestaying silent, exactly-once, and a re-run after a REST-triggered reload.ctest -R "sched|plugin|settings"passes 12/12;activate-moduleandrest-modules-v1/v2pass against theload_single_pluginchange.Note: the reload case needs a build with a web backend (the
mongoose-less build tree has no WEBServer module).🤖 Generated with Claude Code