Skip to content

feat: use ding for ordered go routine shutdown order#896

Merged
steveiliop56 merged 8 commits into
mainfrom
feat/ding
May 27, 2026
Merged

feat: use ding for ordered go routine shutdown order#896
steveiliop56 merged 8 commits into
mainfrom
feat/ding

Conversation

@steveiliop56
Copy link
Copy Markdown
Member

@steveiliop56 steveiliop56 commented May 24, 2026

Summary by CodeRabbit

  • Refactor
    • Replaced ad-hoc goroutine/waitgroup shutdown with a prioritized lifecycle manager to improve orderly service and listener shutdown.
  • Chores
    • Converted background routines and listeners to context-driven cancellation for cleaner graceful termination and resource cleanup.
    • Added lifecycle management dependency.
  • Tests
    • Updated test harnesses to use the new lifecycle wiring.

Review Change Stack

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label May 24, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: eaee86ca-74ca-487c-ad2f-240d846cbd26

📥 Commits

Reviewing files that changed from the base of the PR and between fe14133 and ef5445f.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • go.mod
  • internal/bootstrap/app_bootstrap.go
  • internal/bootstrap/service_bootstrap.go
  • internal/controller/proxy_controller_test.go
  • internal/controller/user_controller_test.go
  • internal/middleware/context_middleware_test.go
  • internal/service/auth_service.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • internal/controller/user_controller_test.go
  • internal/service/auth_service.go
  • internal/controller/proxy_controller_test.go
  • internal/middleware/context_middleware_test.go
  • internal/bootstrap/app_bootstrap.go

📝 Walkthrough

Walkthrough

Replaces sync.WaitGroup coordination with an injected *ding.Ding across bootstrap, router, services, and tests; background goroutines are scheduled with ring priorities and accept context.Context for shutdown.

Changes

Ding Lifecycle Refactor

Layer / File(s) Summary
Dependency and bootstrap foundation
go.mod, internal/bootstrap/app_bootstrap.go
Adds github.com/steveiliop56/ding v0.2.0, imports ding, documents ring priorities, adds ding *ding.Ding to BootstrapApp, and initializes it in Setup().
Router and listener goroutine coordination
internal/bootstrap/router_bootstrap.go
Threads context.Context through listener factory and serve helpers; listeners run via app.ding.Go(...) and use context-aware graceful shutdown with timeout.
Database and app shutdown coordination
internal/bootstrap/app_bootstrap.go
Registers DB close on a critical ding ring, starts dbCleanup and heartbeat via ding, updates routines to accept ctx, and waits on app.ding.Wait() during shutdown.
Service bootstrap constructor wiring
internal/bootstrap/service_bootstrap.go
Passes app.ding to service constructors (LDAP, Tailscale, Auth, OIDC, Kubernetes, Docker) instead of &app.wg.
Service background implementations
internal/service/*
Docker, Kubernetes, LDAP, Tailscale, Auth, and OIDC services accept *ding.Ding, remove stored contexts where present, start background routines via dg.Go(...), and make cleanup/watch loops context-driven.
Test file ding initialization
internal/controller/*_test.go, internal/middleware/*_test.go, internal/service/*_test.go
Tests create ding instances (ding.New(ctx)) and pass them into service constructors instead of constructing/using sync.WaitGroup.

Estimated code review effort: 🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

Suggested labels

lgtm

Suggested reviewers

  • Rycochet
  • scottmckendry

Poem

🐰 The waitgroup snoozed while the ding took the floor,
Rings set the order, listeners closed the door,
Goroutines bowed to context's gentle plea,
Cleanup marched off in tidy harmony,
Rabbit hops off — "All closed! Whee!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: replacing wait-group-based shutdown with the ding lifecycle manager for ordered goroutine shutdown across multiple service files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ding

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
go.mod (1)

143-143: ⚡ Quick win

Dependency should be direct, not indirect.

The ding package is directly imported in app_bootstrap.go and router_bootstrap.go, so it should be listed as a direct dependency (without // indirect). Run go mod tidy to correct this.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go.mod` at line 143, The go.mod entry for github.com/steveiliop56/ding is
marked // indirect but the package is directly imported by app_bootstrap.go and
router_bootstrap.go; fix this by updating module metadata — run `go mod tidy`
(or remove the `// indirect` marker and re-run `go mod tidy`) so
github.com/steveiliop56/ding becomes a direct dependency, then verify imports in
app_bootstrap.go and router_bootstrap.go still build.
internal/bootstrap/app_bootstrap.go (2)

383-386: 💤 Low value

Redundant ticker.Stop() call.

Same issue as heartbeatRoutine — the defer at line 369 handles cleanup.

🧹 Suggested cleanup
 		case <-ctx.Done():
 			app.log.App.Debug().Msg("Stopping database cleanup routine")
-			ticker.Stop()
 			return
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/bootstrap/app_bootstrap.go` around lines 383 - 386, Redundant
explicit ticker.Stop() inside the select case for <-ctx.Done() should be removed
because the ticker is already stopped by the defer ticker.Stop() declared
earlier in the same function; locate the function containing the ticker variable
and the select with the <-ctx.Done() branch (the database cleanup routine) and
delete the ticker.Stop() call from that case so the defer handles cleanup only
once.

359-362: 💤 Low value

Redundant ticker.Stop() call.

Line 361 is unnecessary since defer ticker.Stop() at line 308 already ensures the ticker is stopped when the function returns.

🧹 Suggested cleanup
 		case <-ctx.Done():
 			app.log.App.Debug().Msg("Stopping heartbeat routine")
-			ticker.Stop()
 			return
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/bootstrap/app_bootstrap.go` around lines 359 - 362, Remove the
redundant ticker.Stop() call in the ctx cancellation branch of the heartbeat
routine: the ticker is already stopped by the defer ticker.Stop() declared
earlier (around line 308), so delete the explicit ticker.Stop() inside the case
<-ctx.Done() block in the function handling the heartbeat loop (the routine that
logs "Stopping heartbeat routine") to avoid duplicate cleanup calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@go.mod`:
- Line 143: The go.mod entry for github.com/steveiliop56/ding is marked //
indirect but the package is directly imported by app_bootstrap.go and
router_bootstrap.go; fix this by updating module metadata — run `go mod tidy`
(or remove the `// indirect` marker and re-run `go mod tidy`) so
github.com/steveiliop56/ding becomes a direct dependency, then verify imports in
app_bootstrap.go and router_bootstrap.go still build.

In `@internal/bootstrap/app_bootstrap.go`:
- Around line 383-386: Redundant explicit ticker.Stop() inside the select case
for <-ctx.Done() should be removed because the ticker is already stopped by the
defer ticker.Stop() declared earlier in the same function; locate the function
containing the ticker variable and the select with the <-ctx.Done() branch (the
database cleanup routine) and delete the ticker.Stop() call from that case so
the defer handles cleanup only once.
- Around line 359-362: Remove the redundant ticker.Stop() call in the ctx
cancellation branch of the heartbeat routine: the ticker is already stopped by
the defer ticker.Stop() declared earlier (around line 308), so delete the
explicit ticker.Stop() inside the case <-ctx.Done() block in the function
handling the heartbeat loop (the routine that logs "Stopping heartbeat routine")
to avoid duplicate cleanup calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c938dea0-7bc3-491e-886a-59f09f066b93

📥 Commits

Reviewing files that changed from the base of the PR and between e532cde and f7f979f.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (16)
  • go.mod
  • internal/bootstrap/app_bootstrap.go
  • internal/bootstrap/router_bootstrap.go
  • internal/bootstrap/service_bootstrap.go
  • internal/controller/oidc_controller_test.go
  • internal/controller/proxy_controller_test.go
  • internal/controller/user_controller_test.go
  • internal/controller/well_known_controller_test.go
  • internal/middleware/context_middleware_test.go
  • internal/service/auth_service.go
  • internal/service/docker_service.go
  • internal/service/kubernetes_service.go
  • internal/service/ldap_service.go
  • internal/service/oidc_service.go
  • internal/service/oidc_service_test.go
  • internal/service/tailscale_service.go

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@go.mod`:
- Line 18: The go.mod currently depends on an unstable personal library
"github.com/steveiliop56/ding v0.1.0" for goroutine lifecycle, which is risky
for production; either replace/remove that dependency by switching to a stable
alternative (e.g., use golang.org/x/sync/errgroup with context in your goroutine
coordination code where you currently use ding), or vendor/fork and pin the ding
code under your org with tests and a migration plan, or explicitly document and
accept the risk in project docs and add upgrade/migration steps; locate the
dependency reference "github.com/steveiliop56/ding v0.1.0" in go.mod and update
your code paths that use ding's APIs (the goroutine/waitgroup replacement
functions) to the chosen approach.
- Line 18: The dependency github.com/steveiliop56/ding v0.1.0 lacks demonstrated
goroutine lifecycle guarantees; either replace it with a more established
alternative or add concrete evidence: update code that uses ding to implement
proper context cancellation and coordinated shutdown (use context.Context
propagation and a WaitGroup or equivalent in the components that spawn ding
goroutines), add unit/integration tests that exercise cancellation/shutdown
paths and detect leaks (race detector and deadline-based shutdown tests), and
add CI steps that run go test -race and the shutdown/leak tests; reference the
module name github.com/steveiliop56/ding and the code locations that spawn its
goroutines for these changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2af3978c-94df-4de9-a5f3-00f353793589

📥 Commits

Reviewing files that changed from the base of the PR and between f7f979f and c428b9b.

📒 Files selected for processing (1)
  • go.mod

Comment thread go.mod Outdated
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label May 27, 2026
@steveiliop56 steveiliop56 merged commit faee58c into main May 27, 2026
5 checks passed
@steveiliop56 steveiliop56 deleted the feat/ding branch May 27, 2026 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants