Files
golib/notify/doc.go
2026-01-24 20:35:40 +11:00

149 lines
4.6 KiB
Go

// Package notify provides a thread-safe pub/sub notification system.
//
// The notify package implements a lightweight, in-memory notification system
// where subscribers can register to receive notifications. Each subscriber
// receives notifications through a buffered channel, allowing them to process
// messages at their own pace.
//
// # Features
//
// - Thread-safe concurrent operations
// - Configurable notification buffer size per Notifier
// - Unique subscriber IDs using cryptographic random generation
// - Targeted notifications to specific subscribers
// - Broadcast notifications to all subscribers
// - Idempotent unsubscribe operations
// - Graceful shutdown with Close()
// - Zero external dependencies (uses only Go standard library)
//
// # Basic Usage
//
// Create a notifier and subscribe:
//
// // Create notifier with 50-notification buffer per subscriber
// n := notify.NewNotifier(50)
// defer n.Close()
//
// // Subscribe to receive notifications
// sub, err := n.Subscribe()
// if err != nil {
// log.Fatal(err)
// }
// defer sub.Unsubscribe()
//
// // Listen for notifications
// go func() {
// for notification := range sub.Listen() {
// fmt.Printf("Received: %s - %s\n", notification.Level, notification.Message)
// }
// }()
//
// // Send a targeted notification
// n.Notify(notify.Notification{
// Target: sub.ID,
// Level: notify.LevelInfo,
// Message: "Hello subscriber!",
// })
//
// # Broadcasting
//
// Send notifications to all subscribers:
//
// // Broadcast to all subscribers
// n.NotifyAll(notify.Notification{
// Level: notify.LevelSuccess,
// Title: "System Update",
// Message: "All systems operational",
// })
//
// # Notification Levels
//
// The package provides predefined notification levels:
//
// - LevelSuccess: Success messages
// - LevelInfo: Informational messages
// - LevelWarn: Warning messages
// - LevelError: Error messages
//
// # Buffer Sizing
//
// The buffer size controls how many notifications can be queued per subscriber:
//
// - Small (10-25): Low latency, minimal memory, may drop messages if slow readers
// - Medium (50-100): Balanced approach (recommended for most applications)
// - Large (200-500): High throughput, handles bursts well
// - Unbuffered (0): No queuing, sends block until received
//
// # Thread Safety
//
// All operations are thread-safe and can be called from multiple goroutines:
//
// - Subscribe() - Safe to call concurrently
// - Unsubscribe() - Safe to call concurrently and multiple times
// - Notify() - Safe to call concurrently
// - NotifyAll() - Safe to call concurrently
// - Close() - Safe to call concurrently and multiple times
//
// # Graceful Shutdown
//
// Close the notifier to unsubscribe all subscribers and prevent new subscriptions:
//
// n := notify.NewNotifier(50)
// defer n.Close() // Ensures cleanup
//
// // Use notifier...
// // On defer or explicit Close():
// // - All subscribers are removed
// // - All notification channels are closed
// // - Future Subscribe() calls return error
// // - Notify() and NotifyAll() are no-ops
//
// # Notification Delivery
//
// Notifications are delivered using a TryLock pattern:
//
// - If the subscriber is available, the notification is queued
// - If the subscriber is busy unsubscribing, the notification is dropped
// - This prevents blocking on subscribers that are shutting down
//
// Buffered channels allow multiple notifications to queue, so subscribers
// don't need to read immediately. Once the buffer is full, subsequent
// notifications may be dropped if the subscriber is slow to read.
//
// # Example: Multi-Subscriber System
//
// func main() {
// n := notify.NewNotifier(100)
// defer n.Close()
//
// // Create multiple subscribers
// for i := 0; i < 5; i++ {
// sub, _ := n.Subscribe()
// go func(id int, s *notify.Subscriber) {
// for notif := range s.Listen() {
// log.Printf("Subscriber %d: %s", id, notif.Message)
// }
// }(i, sub)
// }
//
// // Broadcast to all
// n.NotifyAll(notify.Notification{
// Level: notify.LevelInfo,
// Message: "Server starting...",
// })
//
// time.Sleep(time.Second)
// }
//
// # Error Handling
//
// Subscribe() returns an error in these cases:
//
// - Notifier is closed (error: "notifier is closed")
// - Failed to generate unique ID after 10 attempts (extremely rare)
//
// Other operations (Notify, NotifyAll, Unsubscribe) do not return errors
// and handle edge cases gracefully (e.g., notifying non-existent subscribers
// is silently ignored).
package notify