1
0
mirror of https://github.com/redis/go-redis.git synced 2025-07-29 17:41:15 +03:00

feat: add GetHandler method and improve push notification API encapsulation

- Add GetHandler() method to PushNotificationProcessorInterface for better encapsulation
- Add GetPushNotificationHandler() convenience method to Client and SentinelClient
- Remove HasHandlers() check from ProcessPendingNotifications to ensure notifications are always consumed
- Use PushNotificationProcessorInterface in internal pool package for proper abstraction
- Maintain GetRegistry() for backward compatibility and testing
- Update pubsub to use GetHandler() instead of GetRegistry() for cleaner code

Benefits:
- Better API encapsulation - no need to expose entire registry
- Cleaner interface - direct access to specific handlers
- Always consume push notifications from reader regardless of handler presence
- Proper abstraction in internal pool package
- Backward compatibility maintained
- Consistent behavior across all processor types
This commit is contained in:
Nedyalko Dyakov
2025-06-27 13:59:43 +03:00
parent ad16b21487
commit d3f61973c1
4 changed files with 37 additions and 20 deletions

View File

@ -96,17 +96,23 @@ func (r *PushNotificationRegistry) GetRegisteredPushNotificationNames() []string
return names return names
} }
// HasHandlers returns true if there are any handlers registered. // GetHandler returns the handler for a specific push notification name.
func (r *PushNotificationRegistry) HasHandlers() bool { // Returns nil if no handler is registered for the given name.
func (r *PushNotificationRegistry) GetHandler(pushNotificationName string) PushNotificationHandler {
r.mu.RLock() r.mu.RLock()
defer r.mu.RUnlock() defer r.mu.RUnlock()
return len(r.handlers) > 0 handler, exists := r.handlers[pushNotificationName]
if !exists {
return nil
}
return handler
} }
// PushNotificationProcessorInterface defines the interface for push notification processors. // PushNotificationProcessorInterface defines the interface for push notification processors.
type PushNotificationProcessorInterface interface { type PushNotificationProcessorInterface interface {
GetRegistry() *PushNotificationRegistry GetHandler(pushNotificationName string) PushNotificationHandler
GetRegistry() *PushNotificationRegistry // For backward compatibility and testing
ProcessPendingNotifications(ctx context.Context, rd *proto.Reader) error ProcessPendingNotifications(ctx context.Context, rd *proto.Reader) error
RegisterHandler(pushNotificationName string, handler PushNotificationHandler, protected bool) error RegisterHandler(pushNotificationName string, handler PushNotificationHandler, protected bool) error
} }
@ -123,16 +129,20 @@ func NewPushNotificationProcessor() *PushNotificationProcessor {
} }
} }
// GetRegistry returns the push notification registry. // GetHandler returns the handler for a specific push notification name.
// Returns nil if no handler is registered for the given name.
func (p *PushNotificationProcessor) GetHandler(pushNotificationName string) PushNotificationHandler {
return p.registry.GetHandler(pushNotificationName)
}
// GetRegistry returns the push notification registry for internal use.
// This method is primarily for testing and internal operations.
func (p *PushNotificationProcessor) GetRegistry() *PushNotificationRegistry { func (p *PushNotificationProcessor) GetRegistry() *PushNotificationRegistry {
return p.registry return p.registry
} }
// ProcessPendingNotifications checks for and processes any pending push notifications. // ProcessPendingNotifications checks for and processes any pending push notifications.
func (p *PushNotificationProcessor) ProcessPendingNotifications(ctx context.Context, rd *proto.Reader) error { func (p *PushNotificationProcessor) ProcessPendingNotifications(ctx context.Context, rd *proto.Reader) error {
if !p.registry.HasHandlers() {
return nil
}
// Check if there are any buffered bytes that might contain push notifications // Check if there are any buffered bytes that might contain push notifications
if rd.Buffered() == 0 { if rd.Buffered() == 0 {
@ -233,6 +243,11 @@ func NewVoidPushNotificationProcessor() *VoidPushNotificationProcessor {
return &VoidPushNotificationProcessor{} return &VoidPushNotificationProcessor{}
} }
// GetHandler returns nil for void processor since it doesn't maintain handlers.
func (v *VoidPushNotificationProcessor) GetHandler(pushNotificationName string) PushNotificationHandler {
return nil
}
// GetRegistry returns nil for void processor since it doesn't maintain handlers. // GetRegistry returns nil for void processor since it doesn't maintain handlers.
func (v *VoidPushNotificationProcessor) GetRegistry() *PushNotificationRegistry { func (v *VoidPushNotificationProcessor) GetRegistry() *PushNotificationRegistry {
return nil return nil

View File

@ -28,9 +28,7 @@ func TestPushNotificationRegistry(t *testing.T) {
registry := redis.NewPushNotificationRegistry() registry := redis.NewPushNotificationRegistry()
// Test initial state // Test initial state
if registry.HasHandlers() { // Registry starts empty (no need to check HasHandlers anymore)
t.Error("Registry should not have handlers initially")
}
commands := registry.GetRegisteredPushNotificationNames() commands := registry.GetRegisteredPushNotificationNames()
if len(commands) != 0 { if len(commands) != 0 {
@ -49,10 +47,7 @@ func TestPushNotificationRegistry(t *testing.T) {
t.Fatalf("Failed to register handler: %v", err) t.Fatalf("Failed to register handler: %v", err)
} }
if !registry.HasHandlers() { // Verify handler was registered by checking registered names
t.Error("Registry should have handlers after registration")
}
commands = registry.GetRegisteredPushNotificationNames() commands = registry.GetRegisteredPushNotificationNames()
if len(commands) != 1 || commands[0] != "TEST_COMMAND" { if len(commands) != 1 || commands[0] != "TEST_COMMAND" {
t.Errorf("Expected ['TEST_COMMAND'], got %v", commands) t.Errorf("Expected ['TEST_COMMAND'], got %v", commands)
@ -803,7 +798,6 @@ func TestPushNotificationRegistryConcurrency(t *testing.T) {
registry.HandleNotification(context.Background(), notification) registry.HandleNotification(context.Background(), notification)
// Check registry state // Check registry state
registry.HasHandlers()
registry.GetRegisteredPushNotificationNames() registry.GetRegisteredPushNotificationNames()
} }
}(i) }(i)
@ -815,10 +809,6 @@ func TestPushNotificationRegistryConcurrency(t *testing.T) {
} }
// Verify registry is still functional // Verify registry is still functional
if !registry.HasHandlers() {
t.Error("Registry should have handlers after concurrent operations")
}
commands := registry.GetRegisteredPushNotificationNames() commands := registry.GetRegisteredPushNotificationNames()
if len(commands) == 0 { if len(commands) == 0 {
t.Error("Registry should have registered commands after concurrent operations") t.Error("Registry should have registered commands after concurrent operations")

View File

@ -837,6 +837,12 @@ func (c *Client) GetPushNotificationProcessor() PushNotificationProcessorInterfa
return c.pushProcessor return c.pushProcessor
} }
// GetPushNotificationHandler returns the handler for a specific push notification name.
// Returns nil if no handler is registered for the given name.
func (c *Client) GetPushNotificationHandler(pushNotificationName string) PushNotificationHandler {
return c.pushProcessor.GetHandler(pushNotificationName)
}
type PoolStats pool.Stats type PoolStats pool.Stats
// PoolStats returns connection pool stats. // PoolStats returns connection pool stats.

View File

@ -522,6 +522,12 @@ func (c *SentinelClient) GetPushNotificationProcessor() PushNotificationProcesso
return c.pushProcessor return c.pushProcessor
} }
// GetPushNotificationHandler returns the handler for a specific push notification name.
// Returns nil if no handler is registered for the given name.
func (c *SentinelClient) GetPushNotificationHandler(pushNotificationName string) PushNotificationHandler {
return c.pushProcessor.GetHandler(pushNotificationName)
}
// RegisterPushNotificationHandler registers a handler for a specific push notification name. // RegisterPushNotificationHandler registers a handler for a specific push notification name.
// Returns an error if a handler is already registered for this push notification name. // Returns an error if a handler is already registered for this push notification name.
// If protected is true, the handler cannot be unregistered. // If protected is true, the handler cannot be unregistered.