perf(actions): debounce runner heartbeat writes and throttle task picks - #38281
Merged
Merged
Conversation
Two runner-poll load reductions that need no DB schema changes: - Debounce last_online/last_active: skip the per-poll and per-UpdateLog runner status writes, persisting only when stale enough to affect the active/offline status (ShouldPersistLastOnline/ShouldPersistLastActive). - Bound concurrent task-pick transactions with an in-process semaphore (MAX_CONCURRENT_TASK_PICKS) so a fleet polling together can't stampede the assignment query; throttled polls retry without advancing the runner's tasks version. Assisted-by: Claude:claude-opus-4-8
…oll-nodb # Conflicts: # models/actions/runner_test.go
Zettat123
approved these changes
Jul 6, 2026
lunny
approved these changes
Jul 7, 2026
bircni
enabled auto-merge (squash)
July 7, 2026 18:57
lunny
pushed a commit
that referenced
this pull request
Jul 7, 2026
…ks (#38281) (#38368) Backport #38281 by @bircni 3 reductions in the DB load generated by many runners polling `FetchTask`: **1. Debounce runner heartbeat writes** Every poll wrote `last_online`, and every `UpdateTask`/`UpdateLog` wrote `last_active` — while a runner streams logs that is many writes per second per runner. These are now persisted only when stale enough to actually affect the active/offline status (`ShouldPersistLastOnline` / `ShouldPersistLastActive`), using the existing columns. **2. Throttle concurrent task picks** A new in-process semaphore (`MAX_CONCURRENT_TASK_PICKS`) bounds how many runners run the task-assignment transaction at once, so a fleet polling together cannot stampede the query. Throttled polls retry on their next poll without advancing the runner's tasks version. **3. Paginate the task-pick query** `CreateTaskForRunner` previously loaded every waiting job in the runner's scope into memory on each poll (no `LIMIT`). Now it pages through the waiting backlog oldest-first with `LIMIT`, claiming the first label-matching job. Co-authored-by: bircni <bircni@icloud.com> Co-authored-by: Zettat123 <zettat123@gmail.com>
zjjhot
added a commit
to zjjhot/gitea
that referenced
this pull request
Jul 9, 2026
* 'main' of https://github.com/go-gitea/gitea: (28 commits) enhance(actions): only create filtered-out workflow commit status for required contexts (go-gitea#38371) fix(ui): restore commits table column widths (go-gitea#38379) test(e2e): fix race in pdf file render test (go-gitea#38380) refactor: introduce ActivePageTimer to help to do partial page refresh (go-gitea#38372) [skip ci] Updated translations via Crowdin chore(typo): fix grammar in comments, API docs and error messages (go-gitea#38370) fix: golang html template url escaping (go-gitea#38363) perf(actions): debounce runner heartbeat writes and throttle task picks (go-gitea#38281) fix(mirror): disable HTTP redirects on pull mirror sync (go-gitea#38320) chore(deps): update dependency djlint to v1.40.1 (go-gitea#38354) fix(deps): update npm dependencies (go-gitea#38352) chore(deps): update action dependencies (go-gitea#38353) fix(deps): update go dependencies (go-gitea#38346) fix: minio init check (go-gitea#38355) fix(pulls): add `branch-name` option for `DEFAULT_TITLE_SOURCE` (go-gitea#38356) fix: org project view assignee list (go-gitea#38357) feat(webhook): add reviewer name to MS Teams review request notifications (go-gitea#38289) chore(deps): update action dependencies (go-gitea#38340) chore: Upgrade xorm to 1.4.1 (go-gitea#38224) chore(deps): update tool dependencies (go-gitea#38344) ...
zjjhot
added a commit
to zjjhot/gitea
that referenced
this pull request
Jul 9, 2026
* main: enhance(actions): only create filtered-out workflow commit status for required contexts (go-gitea#38371) fix(ui): restore commits table column widths (go-gitea#38379) test(e2e): fix race in pdf file render test (go-gitea#38380) refactor: introduce ActivePageTimer to help to do partial page refresh (go-gitea#38372) [skip ci] Updated translations via Crowdin chore(typo): fix grammar in comments, API docs and error messages (go-gitea#38370) fix: golang html template url escaping (go-gitea#38363) perf(actions): debounce runner heartbeat writes and throttle task picks (go-gitea#38281) fix(mirror): disable HTTP redirects on pull mirror sync (go-gitea#38320) chore(deps): update dependency djlint to v1.40.1 (go-gitea#38354) fix(deps): update npm dependencies (go-gitea#38352) chore(deps): update action dependencies (go-gitea#38353) fix(deps): update go dependencies (go-gitea#38346) fix: minio init check (go-gitea#38355) fix(pulls): add `branch-name` option for `DEFAULT_TITLE_SOURCE` (go-gitea#38356)
zeekay
pushed a commit
to hanzoai/forge
that referenced
this pull request
Jul 26, 2026
…ks (go-gitea#38281) 3 reductions in the DB load generated by many runners polling `FetchTask`: **1. Debounce runner heartbeat writes** Every poll wrote `last_online`, and every `UpdateTask`/`UpdateLog` wrote `last_active` — while a runner streams logs that is many writes per second per runner. These are now persisted only when stale enough to actually affect the active/offline status (`ShouldPersistLastOnline` / `ShouldPersistLastActive`), using the existing columns. **2. Throttle concurrent task picks** A new in-process semaphore (`MAX_CONCURRENT_TASK_PICKS`) bounds how many runners run the task-assignment transaction at once, so a fleet polling together cannot stampede the query. Throttled polls retry on their next poll without advancing the runner's tasks version. **3. Paginate the task-pick query** `CreateTaskForRunner` previously loaded every waiting job in the runner's scope into memory on each poll (no `LIMIT`). Now it pages through the waiting backlog oldest-first with `LIMIT`, claiming the first label-matching job. --------- Co-authored-by: Zettat123 <zettat123@gmail.com>
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.
Split out of #38150, which is being broken into smaller, independently reviewable PRs. This one contains the parts that need no database schema change and can be reviewed/merged on its own.
3 reductions in the DB load generated by many runners polling
FetchTask:1. Debounce runner heartbeat writes
Every poll wrote
last_online, and everyUpdateTask/UpdateLogwrotelast_active— while a runner streams logs that is many writes per second per runner. These are now persisted only when stale enough to actually affect the active/offline status (ShouldPersistLastOnline/ShouldPersistLastActive), using the existing columns.2. Throttle concurrent task picks
A new in-process semaphore (
MAX_CONCURRENT_TASK_PICKS) bounds how many runners run the task-assignment transaction at once, so a fleet polling together cannot stampede the query. Throttled polls retry on their next poll without advancing the runner's tasks version.3. Paginate the task-pick query
CreateTaskForRunnerpreviously loaded every waiting job in the runner's scope into memory on each poll (noLIMIT). Now it pages through the waiting backlog oldest-first withLIMIT, claiming the first label-matching job.No migration — uses existing columns and adds one config option.