fix(watchdog): alert on sustained goroutine breach, add hard ceiling (HUB-3) #104
Open
bot
wants to merge 1 commit from
fix/HUB-3-watchdog-sustained-breach into main
pull from: fix/HUB-3-watchdog-sustained-breach
merge into: pokebedrock:main
pokebedrock:main
pokebedrock:fix/HUB-2-heap-profile-attachment
pokebedrock:feat/content-creator-beta-access
pokebedrock:feat/split-res-packs
pokebedrock:feat/rogue-experience
pokebedrock:fleet-admin-ui
pokebedrock:remove-udp-relays
pokebedrock:migrate-to-new-website
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.48.0
pokebedrock:dev-servers
pokebedrock:dependabot/go_modules/go_modules-607a02e571
pokebedrock:dependabot/github_actions/actions/setup-go-7
pokebedrock:dependabot/go_modules/github.com/sandertv/gophertunnel-1.57.1
pokebedrock:dependabot/go_modules/github.com/df-mc/dragonfly-0.11.0
pokebedrock:dependabot/go_modules/golang.org/x/term-0.45.0
pokebedrock:dependabot/go_modules/golang.org/x/text-0.40.0
pokebedrock:v0.11.0-migration
pokebedrock:dependabot/go_modules/github.com/schollz/progressbar/v3-3.19.1
pokebedrock:dependabot/go_modules/github.com/sandertv/go-raknet-1.15.1
pokebedrock:dependabot/github_actions/actions/checkout-7
pokebedrock:dependabot/github_actions/actions/setup-go-6
pokebedrock:dependabot/github_actions/softprops/action-gh-release-3
pokebedrock:great-improvements-and-cleanup
pokebedrock:dependabot/go_modules/golang.org/x/text-0.38.0
pokebedrock:dependabot/go_modules/go_modules-c3a371b575
pokebedrock:dependabot/go_modules/golang.org/x/text-0.37.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.46.2
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.46.0
pokebedrock:improve-afk
pokebedrock:dependabot/go_modules/golang.org/x/text-0.36.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.45.1
pokebedrock:dependabot/go_modules/go_modules-a978bc362c
pokebedrock:dependabot/go_modules/golang.org/x/text-0.35.0
pokebedrock:dependabot/go_modules/github.com/samber/lo-1.53.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.43.0
pokebedrock:dependabot/go_modules/github.com/gin-gonic/gin-1.12.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.42.0
pokebedrock:dependabot/go_modules/github.com/sandertv/gophertunnel-1.53.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.41.0
pokebedrock:dependabot/go_modules/golang.org/x/text-0.33.0
pokebedrock:dependabot/go_modules/github.com/sandertv/go-raknet-1.15.0
pokebedrock:dependabot/go_modules/golang.org/x/text-0.32.0
pokebedrock:dependabot/go_modules/go_modules-15eab1e1d8
pokebedrock:feature/parkour
pokebedrock:dependabot/go_modules/go_modules-dd7da38a6b
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.40.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.38.0
pokebedrock:dependabot/go_modules/golang.org/x/text-0.31.0
pokebedrock:dependabot/go_modules/github.com/sandertv/gophertunnel-1.51.0
pokebedrock:dependabot/go_modules/github.com/df-mc/dragonfly-0.10.9
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.36.2
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.36.1
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.36.0
pokebedrock:dependabot/go_modules/github.com/samber/lo-1.52.0
pokebedrock:dependabot/go_modules/golang.org/x/text-0.30.0
pokebedrock:dependabot/go_modules/github.com/sandertv/gophertunnel-1.50.1
pokebedrock:dependabot/go_modules/github.com/df-mc/dragonfly-0.10.8
pokebedrock:dependabot/go_modules/github.com/restartfu/gophig-0.1.0
pokebedrock:dependabot/go_modules/github.com/sandertv/gophertunnel-1.50.0
pokebedrock:dependabot/go_modules/github.com/df-mc/dragonfly-0.10.6
pokebedrock:dependabot/go_modules/github.com/sandertv/gophertunnel-1.49.1
pokebedrock:dependabot/go_modules/github.com/gin-gonic/gin-1.11.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.35.3
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.35.2
pokebedrock:dependabot/go_modules/golang.org/x/text-0.29.0
pokebedrock:cursor/fix-linting-errors-and-improve-code-quality-c53d
pokebedrock:cursor/resolve-magic-number-linter-errors-ae43
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.35.1
pokebedrock:dependabot/go_modules/golang.org/x/text-0.28.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.35.0
pokebedrock:dependabot/go_modules/go_modules-985326579b
pokebedrock:dependabot/go_modules/golang.org/x/text-0.27.0
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.34.1
pokebedrock:dependabot/go_modules/github.com/go-jose/go-jose/v4-4.1.1
pokebedrock:dependabot/go_modules/go_modules-1bf47a65e7
pokebedrock:support/gobds
pokebedrock:dependabot/go_modules/github.com/df-mc/dragonfly-0.10.5
pokebedrock:dependabot/go_modules/github.com/getsentry/sentry-go-0.34.0
pokebedrock:dependabot/go_modules/golang.org/x/text-0.26.0
pokebedrock:feature/gobds-support
pokebedrock:dependabot/go_modules/golang.org/x/text-0.25.0
pokebedrock:dependabot/go_modules/go_modules-bbb8b02913
pokebedrock:dependabot/go_modules/golang.org/x/text-0.24.0
pokebedrock:dependabot/go_modules/go_modules-c153b83258
pokebedrock:dependabot/go_modules/golang.org/x/text-0.23.0
pokebedrock:alert-autofix-1
pokebedrock:dependabot/go_modules/github.com/df-mc/dragonfly-0.10.2
pokebedrock:dependabot/go_modules/go_modules-6be307652c
No reviewers
Labels
Clear labels
blocked
automation label
bug
Something isn't working
dependencies
Pull requests that update a dependency file
documentation
Improvements or additions to documentation
duplicate
This issue or pull request already exists
enhancement
New feature or request
github_actions
Pull requests that update GitHub Actions code
go
Pull requests that update Go code
good first issue
Good for newcomers
help wanted
Extra attention is needed
in-progress
automation label
invalid
This doesn't seem right
question
Further information is requested
ready-to-fix
automation label
source:discord
automation label
source:sentry
automation label
source:server-logs
automation label
triage-needed
automation label
wontfix
This will not be worked on
No labels
blocked
bug
dependencies
documentation
duplicate
enhancement
github_actions
go
good first issue
help wanted
in-progress
invalid
question
ready-to-fix
source:discord
source:sentry
source:server-logs
triage-needed
wontfix
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
pokebedrock/pokebedrock-hub!104
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/HUB-3-watchdog-sustained-breach"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Do not merge without Curry's OK.
Sentry: POKEBEDROCK-HUB-3 (
watchdog: goroutine count high). 337 events in 7d, 959 lifetime. Over Sep 17 to Oct 17: goroutines median 956, p90 1,315, max 1,820, never ≥2,000. 607 of 664 episodes were a single 30s check. That points to short load spikes, not a leak.Change
GoroutineThreshold + GoroutinesPerPlayer × players) must be breached forSustainChecksconsecutive checks (default 3, i.e. 90s) before a Sentry alert. Transient breaches log at Warn. The streak resets on a healthy check.goroutine_ceilingcondition (default 3000) alerts on the first check, regardless of players or SustainChecks. It also caps the soft limit. The ceiling and the soft pileup are mutually exclusive, so a 4k pile-up gives one goroutine alert.GoroutinesPerPlayer = 0now means the default (12) on top of the 800 base. A negative value opts out and keeps the fixed threshold. The hub needs no host config edit.["watchdog", <condition>], so counts in the message don't split issues. This opens one new Sentry issue forgoroutine_pileup. Leave HUB-3 open until the new one is confirmed.SustainChecksandGoroutineHardCeilingare wired throughconfig.go/loadWatchdog/config.example.toml.Tests
go vet ./...andgo test ./...pass;go test -race ./pokebedrock/watchdog/...passes. Two existing cases were updated (the deadlock signature now expectsgoroutine_ceiling; the fixed-threshold opt-out now uses -1). New cases: defaults, clamp to ceiling, ceiling bypasses gate, sustain gate + reset, SustainChecks=1, stall/heap not gated, ceiling < threshold raised.Rollout
This repo has no PR CI; release.yml runs vet+test on main. It takes effect only after merge (v0.1.64) and a hub restart on ns1018631, and both need Curry's OK. One restart picks up both #103 and this. After 24h, re-tune GoroutinesPerPlayer from the first
goroutines.txtattachment.Risk: low; this only changes monitoring. Worst case, a real slow leak under 3000 alerts 90s later than it does today.
Stacked follow-up for HUB-2 (heap profile on heap alerts) is coming as a separate PR based on this branch.
Verdict: no blockers. Fine to merge once Curry OKs it. Posted as COMMENT because the PR is bot-authored, so it still needs a human approval.
I checked it locally because this repo has no PR CI. At
3ca70e36,go vet ./pokebedrock/watchdog/,go test -race ./pokebedrock/watchdog/andgo build ./...all pass.The sustain gate, the ceiling-vs-soft exclusivity and the clamp all hold up when I trace them. Notes below, most important first:
SetFingerprint({"watchdog", cond})runs forworld_stallandheap_pressureas well. After the restart, stall and heap events open new Sentry issues too, including the heap events HUB-2 / #105 are chasing, andgoroutine_ceilinggets its own issue. The body says onlygoroutine_pileupopens a new issue. Please fix the body, and leave HUB-2 open until the new heap issue is confirmed, not just HUB-3 (inline).GoroutineThreshold, every soft breach (>= threshold) becomes a ceiling breach, andgoroutineLimitis capped at that same value. So the sustain gate and per-player headroom both go dead, which is the outcome the comment says it prevents. Either clamp toGoroutineThreshold + 1or above (or log a config warning), or reword the comment to say a misconfigured ceiling disables the gate.TestCeilingBelowThresholdRaisedlocks in the current behavior, so update it with the fix (inline).GoroutinesPerPlayer = 0used to mean a fixed threshold and now means 12 per player. The body states this is intended. Still, call it out in the release notes for v0.1.64 so nobody reads an old config as "fixed" (inline onconfig.example.toml).goroutine_ceilingcheck yields nocondGoroutinesalert, sobreachedstays false and the streak goes to 0. With a sequence like 2.9k, 2.95k, 3.1k, 2.9k, the soft alert has to rebuild 3 checks after the ceiling fired. That's harmless since the ceiling already paged, but say so in thegateSustaineddoc, or count a ceiling check as a breach so the streak tells the truth (inline).goroutine_streakis reported in the Sentry context of stall and heap alerts too, where it means nothing. Only set it for the goroutine conditions.@param/@returnsstyle isn't idiomatic godoc, but the file already uses it, so this is consistent. No change needed.Rollout is unchanged from the body: merge (v0.1.64) plus a hub restart on ns1018631, both on Curry's call.
@ -74,3 +74,3 @@WorldExecTimeout = "10s" # Max time a probe world task may take before the world owner is considered stalled (login-blocking deadlock). Config key kept for deployed configs.GoroutineThreshold = 800 # Goroutine count at/above which an alert is raised.GoroutinesPerPlayer = 0 # Extra goroutines per online player. Limit = GoroutineThreshold + N*players. 0 keeps the fixed threshold.GoroutinesPerPlayer = 12 # Extra goroutines per online player. Limit = min(GoroutineThreshold + N*players, GoroutineHardCeiling). 0 = default (12), negative = fixed threshold.Semantics flip for deployed configs: an existing
GoroutinesPerPlayer = 0used to mean a fixed threshold and now means 12 per player. Put this in the v0.1.64 release notes.@ -99,0 +129,4 @@// A ceiling below the base threshold would turn every soft breach into a// ceiling breach; keep it at least the base.if c.GoroutineHardCeiling < c.GoroutineThreshold {c.GoroutineHardCeiling = c.GoroutineThresholdRaising the ceiling to exactly the threshold makes every soft breach (
>= threshold) a ceiling breach, andgoroutineLimitcaps at the same value. So the sustain gate and per-player headroom go dead, which is the case this comment says it prevents. Either clamp above the threshold and log a config warning, or reword the comment.@ -237,0 +323,4 @@a.message += fmt.Sprintf(" (sustained %d checks)", w.goroutineStreak)out = append(out, a)}if !breached {A ceiling-level check has no
condGoroutinesalert, so this resets the streak. The soft alert then needs 3 fresh checks after the ceiling fired. That's harmless, but either document it or count a ceiling check as a breach.@ -286,2 +380,4 @@scope.SetLevel(a.level)scope.SetTag("watchdog_condition", string(a.cond))// Counts in the message must not split issues: one issue per condition.scope.SetFingerprint([]string{"watchdog", string(a.cond)})This fingerprint applies to every condition, so
world_stallandheap_pressurere-group into new Sentry issues too (HUB-2 included), andgoroutine_ceilinggets its own. Please fix the PR body, which says only goroutine_pileup opens a new issue.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.