Files
common/message/msg_plugin_manager.go

134 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package message
import (
"context"
"fmt"
"sync"
"time"
"github.com/gogf/gf/v2/frame/g"
)
// MessageType 消息队列类型
type messageType string
const (
// MessageRedis Redis 消息队列
MessageRedis messageType = "redis"
// MessageRabbitMQ RabbitMQ 消息队列
MessageRabbitMQ messageType = "rabbitmq"
// MessageNATS NATS 消息队列
MessageNATS messageType = "nats"
)
// configFactory 消息队列配置工厂函数类型
type configFactory func() messageUtil
// PluginManager 消息队列插件管理器
type pluginManager struct {
mu sync.RWMutex
instances map[messageType]messageUtil // 已连接的插件实例
}
var (
defaultPluginManager = newPluginManager()
// 不再支持默认插件类型,必须显式指定类型
)
// newPluginManager 创建插件管理器
func newPluginManager() *pluginManager {
return &pluginManager{
instances: make(map[messageType]messageUtil),
}
}
// RegisterPlugin 注册消息队列插件
// 所有插件必须通过此方法注册,自动进行连接检测
// 只有连接成功的插件才会被注册,连接失败的插件不会被注册
// 异步无限重连,只有连接成功了才注册
func registerPlugin(msgType messageType, factory configFactory) error {
if factory == nil {
return fmt.Errorf("factory cannot be nil")
}
// 创建实例
instance := factory()
ctx := context.Background()
// 开启异步连接,无限重连直到成功
go func() {
retryInterval := 2 * time.Second
maxInterval := 30 * time.Second
for {
select {
case <-ctx.Done():
g.Log().Errorf(ctx, "❌ [%s] 注册被取消", msgType)
return
default:
// 尝试连接使用Reconnect方法
if err := instance.reconnect(ctx); err == nil {
// 连接成功,注册插件
if err := defaultPluginManager.register(msgType, instance); err != nil {
g.Log().Errorf(ctx, "❌ [%s] 注册插件失败: %v", msgType, err)
instance.close(ctx)
} else {
g.Log().Infof(ctx, "✅ [%s] 插件注册成功", msgType)
}
return
}
// 连接失败,记录日志并等待重试
g.Log().Warningf(ctx, "⚠️ [%s] 连接失败,%v 后重试...", msgType, retryInterval)
select {
case <-time.After(retryInterval):
// 增加重试间隔,但不超过最大值
retryInterval *= 2
if retryInterval > maxInterval {
retryInterval = maxInterval
}
case <-ctx.Done():
g.Log().Errorf(ctx, "❌ [%s] 注册被取消", msgType)
return
}
}
}
}()
return nil
}
// register 注册插件(内部方法)
func (m *pluginManager) register(msgType messageType, instance messageUtil) error {
m.mu.Lock()
defer m.mu.Unlock()
m.instances[msgType] = instance
return nil
}
// GetMsgPlugin 获取消息队列插件
func GetMsgPlugin(msgType messageType) (messageUtil, error) {
defaultPluginManager.mu.RLock()
instance, ok := defaultPluginManager.instances[msgType]
defaultPluginManager.mu.RUnlock()
if !ok {
return nil, fmt.Errorf("unsupported message type: %s", msgType)
}
return instance, nil
}
// GetSupportedTypes 获取所有已注册的插件类型
func GetSupportedTypes() []messageType {
defaultPluginManager.mu.RLock()
defer defaultPluginManager.mu.RUnlock()
types := make([]messageType, 0, len(defaultPluginManager.instances))
for t := range defaultPluginManager.instances {
types = append(types, t)
}
return types
}