Skip to content

Fix: do not query the run status of every scheduled task in the schedule loop - #3072

Open
TheBeast85 wants to merge 1 commit into
greenbone:mainfrom
TheBeast85:perf/schedule-loop-run-status
Open

Fix: do not query the run status of every scheduled task in the schedule loop#3072
TheBeast85 wants to merge 1 commit into
greenbone:mainfrom
TheBeast85:perf/schedule-loop-run-status

Conversation

@TheBeast85

@TheBeast85 TheBeast85 commented Jul 30, 2026

Copy link
Copy Markdown

What

  • Select tasks.run_status in init_task_schedule_iterator and read it from the row
  • In task_schedule_iterator_stop_due, check the run status before looking for a running report

Why

The three due checks each asked the database for the run status separately, once per row and once per pass of the schedule loop, and task_running_report asks for it again - three identical queries per scheduled task and pass. They all run inside the transaction that the iterator opens with sql_begin_immediate_giveup, so the loop holds that transaction while issuing them.

Only a task that is requested, queued or running can have a running report, so that lookup is not needed for any of the others.

Idle with 7 scheduled tasks the SELECT run_status FROM tasks statements go from 108 to 0 per minute. The count is three per scheduled task and pass, so it grows with the number of scheduled tasks: with 4503 of them it was 40527 statements per 30 s and the loop held its transaction for about 850 ms every 10 seconds.

The run status column is appended to the select list, so the existing column indices are untouched, and the accessor is static because nothing outside the file needs it.

Checklist

  • Tests: schedules still evaluated, nothing new in the log

…ule loop

init_task_schedule_iterator selects everything the due checks need except the
task run status, so task_schedule_iterator_start_due, _stop_due and
_timed_out each ask the database for it separately, once per row and once per
pass of the schedule loop.  task_running_report asks for the run status as
well, which makes three identical queries per scheduled task and pass.

They all run inside the transaction that init_task_schedule_iterator opens
with sql_begin_immediate_giveup, so the loop holds that transaction while it
issues them.

Select tasks.run_status with the rest of the row and read it from there.  It
is appended to the select list, so the existing column indices are untouched,
and the accessor is static because nothing outside this file needs it.

In _stop_due, check the run status before looking for a running report: a
task that is not requested, queued or running has none, so the report lookup
(and the run status query inside it) is only needed for tasks that are on
their way.

    idle, 7 scheduled tasks, 60 s
    "SELECT run_status FROM tasks" statements
    before: 108      after: 0

The count is three per scheduled task per pass, so it grows with the number
of scheduled tasks: on an installation with 4503 of them it was 40527
statements per 30 s, and the loop held its transaction for ~850 ms every
10 seconds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@TheBeast85
TheBeast85 requested review from a team as code owners July 30, 2026 10:08
@greenbonebot
greenbonebot enabled auto-merge (rebase) July 30, 2026 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant