mirror of
https://github.com/binwiederhier/ntfy.git
synced 2026-11-10 14:44:04 +08:00
The cluster now owns the maintenance state (Cluster.Maintenance) instead of the server keeping its own copy; the server keeps only the draining phase. Role() returns the role the node acts in (passive in maintenance mode), so /v1/ready says "role":"passive","maintenance":true. Cluster.HasActivePeer replaces the server's own walk over Members. A single-node server no longer logs about maintenance mode on every shutdown. The stream registry moves to its own file, with unit tests.
62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
// streamRegistry tracks the open subscriber connections (HTTP streams and WebSockets), one entry
|
|
// per connection however many topics it subscribes to, so a drain can close them one at a time.
|
|
// Polls are not streams: they end on their own.
|
|
type streamRegistry struct {
|
|
nextID int
|
|
cancels map[int]context.CancelFunc
|
|
mu sync.Mutex // Protects nextID and cancels
|
|
}
|
|
|
|
func newStreamRegistry() *streamRegistry {
|
|
return &streamRegistry{
|
|
cancels: make(map[int]context.CancelFunc),
|
|
}
|
|
}
|
|
|
|
// Add registers a stream and returns its ID for Remove
|
|
func (r *streamRegistry) Add(cancel context.CancelFunc) int {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.nextID++
|
|
r.cancels[r.nextID] = cancel
|
|
return r.nextID
|
|
}
|
|
|
|
// Remove forgets a stream that ended; a stream CancelSome already closed is gone already
|
|
func (r *streamRegistry) Remove(id int) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
delete(r.cancels, id)
|
|
}
|
|
|
|
// Len returns the number of open streams
|
|
func (r *streamRegistry) Len() int {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
return len(r.cancels)
|
|
}
|
|
|
|
// CancelSome closes up to n streams, picked in map order (i.e. at random), and returns how
|
|
// many it closed. They are removed right away, so the next call picks others.
|
|
func (r *streamRegistry) CancelSome(n int) int {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
canceled := 0
|
|
for id, cancel := range r.cancels {
|
|
if canceled >= n {
|
|
break
|
|
}
|
|
cancel()
|
|
delete(r.cancels, id)
|
|
canceled++
|
|
}
|
|
return canceled
|
|
}
|