Skip to content

servstate: close service ring buffer on process exit during stop - #925

Open
sundeep8967 wants to merge 2 commits into
canonical:masterfrom
sundeep8967:fix/ringbuffer-close-on-shutdown
Open

servstate: close service ring buffer on process exit during stop#925
sundeep8967 wants to merge 2 commits into
canonical:masterfrom
sundeep8967:fix/ringbuffer-close-on-shutdown

Conversation

@sundeep8967

@sundeep8967 sundeep8967 commented Aug 27, 2026

Copy link
Copy Markdown

Problem

When a service is stopped by the service manager, its log ring buffer was left open. Any log puller or reader iterators would wait until forced termination deadlines or remain open while the service was inactive. Furthermore, attempting to close ring buffers globally in LogManager.Stop() risks closing buffers for services that could still be running.

Solution

  • internals/overlord/servstate/handlers.go:
    • In s.exited(), close s.logs (_ = s.logs.Close()) when the service reaches stateStopped after its process has exited.
    • In s.stop(), close s.logs when the service is stopped while in stateBackoff.
    • In serviceForStart(), allocate a fresh s.logs = servicelog.NewRingBuffer(maxLogBytes) if the service is subsequently restarted and the previous buffer was closed.
  • internals/overlord/servstate/export_test.go:
    • Export ServiceLogBuffer helper for test verification.
  • internals/overlord/servstate/manager_test.go:
    • Add assertions to TestStartStopServices and TestStopDuringBackoff to verify s.logs.Closed() is true after stopping.
  • internals/overlord/logstate/manager_test.go:
    • Fix a pre-existing goroutine leak in TestLabels by calling m.Stop() at the end of the test.

Fixes #681

Testing

  • Verified compilation on Linux (GOOS=linux go test -c ./internals/overlord/servstate).
  • Tested TestStartStopServices and TestStopDuringBackoff with ring buffer closure assertions.
  • Verified internals/overlord/logstate tests (TestTimelyShutdown, TestLabels, TestPlanChange).

@hpidcock

Copy link
Copy Markdown
Member

Hi @sundeep8967,

Thank-you for the PR. It looks like we are trying to close the ring buffers for services that could still be running.
We need to have the service manager close the ring buffer during stop once the process has exited.

@sundeep8967
sundeep8967 force-pushed the fix/ringbuffer-close-on-shutdown branch from 5a10147 to 778721c Compare September 5, 2026 09:38
@sundeep8967 sundeep8967 closed this Sep 5, 2026
@sundeep8967 sundeep8967 reopened this Sep 5, 2026
When a service is stopped by the service manager, its log ring buffer
was left open, meaning any log puller or reader iterators would wait
until forced termination deadlines or remain open while the service
was inactive. Furthermore, attempting to close ring buffers globally in
LogManager.Stop() risks closing buffers for services that may still be
running.

Close the service's log ring buffer (s.logs.Close()) from within the
service manager when the service reaches stopped state once the process
has exited (or when stopped during backoff). If the service is subsequently
restarted, ensure serviceForStart allocates a fresh ring buffer if the
previous one was closed.

Also fix the goroutine leak in TestLabels by ensuring m.Stop() is called
at the end of the test.

Fixes: canonical#681
Signed-off-by: sundeep8967 <sundeep8967@gmail.com>
@sundeep8967
sundeep8967 force-pushed the fix/ringbuffer-close-on-shutdown branch from 778721c to 68aec26 Compare September 6, 2026 09:02
@sundeep8967 sundeep8967 changed the title logstate: close ring buffers in LogManager.Stop() to unblock pullers promptly servstate: close service ring buffer on process exit during stop Sep 6, 2026
@sundeep8967

Copy link
Copy Markdown
Author

Hi @hpidcock,

Thank you for the review and guidance!

I have updated the implementation according to your feedback:

  • Reverted closing all buffers globally in LogManager.Stop().
  • Updated servstate so the service manager closes the service log ring buffer (s.logs.Close()) during stop once the process has exited in s.exited() (and in s.stop() when stopped during backoff).
  • Added logic in serviceForStart() to allocate a fresh ring buffer if the service is restarted after being stopped.
  • Added unit test assertions in TestStartStopServices and TestStopDuringBackoff to verify the ring buffer is closed when the service stops.

Please take another look when you have a moment.

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.

Shutdown has 2s delay when log forwarding is being used

2 participants