mirror of
https://github.com/pgsty/minio.git
synced 2026-07-23 14:10:25 +03:00
non-blocking initialization of bucket target notifications (#15571)
This commit is contained in:
@@ -18,7 +18,6 @@
|
||||
package target
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
@@ -36,7 +35,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
reconnectInterval = 5 // In Seconds
|
||||
reconnectInterval = 5 * time.Second
|
||||
storePrefix = "minio"
|
||||
)
|
||||
|
||||
@@ -107,6 +106,8 @@ func (m MQTTArgs) Validate() error {
|
||||
|
||||
// MQTTTarget - MQTT target.
|
||||
type MQTTTarget struct {
|
||||
lazyInit lazyInit
|
||||
|
||||
id event.TargetID
|
||||
args MQTTArgs
|
||||
client mqtt.Client
|
||||
@@ -120,13 +121,15 @@ func (target *MQTTTarget) ID() event.TargetID {
|
||||
return target.id
|
||||
}
|
||||
|
||||
// HasQueueStore - Checks if the queueStore has been configured for the target
|
||||
func (target *MQTTTarget) HasQueueStore() bool {
|
||||
return target.store != nil
|
||||
}
|
||||
|
||||
// IsActive - Return true if target is up and active
|
||||
func (target *MQTTTarget) IsActive() (bool, error) {
|
||||
if err := target.init(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return target.isActive()
|
||||
}
|
||||
|
||||
func (target *MQTTTarget) isActive() (bool, error) {
|
||||
if !target.client.IsConnectionOpen() {
|
||||
return false, errNotConnected
|
||||
}
|
||||
@@ -147,7 +150,7 @@ func (target *MQTTTarget) send(eventData event.Event) error {
|
||||
}
|
||||
|
||||
token := target.client.Publish(target.args.Topic, target.args.QoS, false, string(data))
|
||||
if !token.WaitTimeout(reconnectInterval * time.Second) {
|
||||
if !token.WaitTimeout(reconnectInterval) {
|
||||
return errNotConnected
|
||||
}
|
||||
return token.Error()
|
||||
@@ -155,8 +158,12 @@ func (target *MQTTTarget) send(eventData event.Event) error {
|
||||
|
||||
// Send - reads an event from store and sends it to MQTT.
|
||||
func (target *MQTTTarget) Send(eventKey string) error {
|
||||
if err := target.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Do not send if the connection is not active.
|
||||
_, err := target.IsActive()
|
||||
_, err := target.isActive()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -182,12 +189,16 @@ func (target *MQTTTarget) Send(eventKey string) error {
|
||||
// Save - saves the events to the store if queuestore is configured, which will
|
||||
// be replayed when the mqtt connection is active.
|
||||
func (target *MQTTTarget) Save(eventData event.Event) error {
|
||||
if err := target.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if target.store != nil {
|
||||
return target.store.Put(eventData)
|
||||
}
|
||||
|
||||
// Do not send if the connection is not active.
|
||||
_, err := target.IsActive()
|
||||
_, err := target.isActive()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -202,17 +213,12 @@ func (target *MQTTTarget) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewMQTTTarget - creates new MQTT target.
|
||||
func NewMQTTTarget(id string, args MQTTArgs, doneCh <-chan struct{}, loggerOnce logger.LogOnce, test bool) (*MQTTTarget, error) {
|
||||
if args.MaxReconnectInterval == 0 {
|
||||
// Default interval
|
||||
// https://github.com/eclipse/paho.mqtt.golang/blob/master/options.go#L115
|
||||
args.MaxReconnectInterval = 10 * time.Minute
|
||||
}
|
||||
func (target *MQTTTarget) init() error {
|
||||
return target.lazyInit.Do(target.initMQTT)
|
||||
}
|
||||
|
||||
if args.KeepAlive == 0 {
|
||||
args.KeepAlive = 10 * time.Second
|
||||
}
|
||||
func (target *MQTTTarget) initMQTT() error {
|
||||
args := target.args
|
||||
|
||||
// Using hex here, to make sure we avoid 23
|
||||
// character limit on client_id according to
|
||||
@@ -229,61 +235,57 @@ func NewMQTTTarget(id string, args MQTTArgs, doneCh <-chan struct{}, loggerOnce
|
||||
SetTLSConfig(&tls.Config{RootCAs: args.RootCAs}).
|
||||
AddBroker(args.Broker.String())
|
||||
|
||||
client := mqtt.NewClient(options)
|
||||
target.client = mqtt.NewClient(options)
|
||||
|
||||
target := &MQTTTarget{
|
||||
id: event.TargetID{ID: id, Name: "mqtt"},
|
||||
args: args,
|
||||
client: client,
|
||||
quitCh: make(chan struct{}),
|
||||
loggerOnce: loggerOnce,
|
||||
token := target.client.Connect()
|
||||
ok := token.WaitTimeout(reconnectInterval)
|
||||
if !ok {
|
||||
return errNotConnected
|
||||
}
|
||||
if token.Error() != nil {
|
||||
return token.Error()
|
||||
}
|
||||
|
||||
token := client.Connect()
|
||||
retryRegister := func() {
|
||||
for {
|
||||
retry:
|
||||
select {
|
||||
case <-doneCh:
|
||||
return
|
||||
case <-target.quitCh:
|
||||
return
|
||||
default:
|
||||
ok := token.WaitTimeout(reconnectInterval * time.Second)
|
||||
if ok && token.Error() != nil {
|
||||
target.loggerOnce(context.Background(),
|
||||
fmt.Errorf("Previous connect failed with %w attempting a reconnect",
|
||||
token.Error()),
|
||||
target.ID().String())
|
||||
time.Sleep(reconnectInterval * time.Second)
|
||||
token = client.Connect()
|
||||
goto retry
|
||||
}
|
||||
if ok {
|
||||
// Successfully connected.
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
yes, err := target.isActive()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !yes {
|
||||
return errNotConnected
|
||||
}
|
||||
|
||||
if target.store != nil {
|
||||
streamEventsFromStore(target.store, target, target.quitCh, target.loggerOnce)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewMQTTTarget - creates new MQTT target.
|
||||
func NewMQTTTarget(id string, args MQTTArgs, loggerOnce logger.LogOnce) (*MQTTTarget, error) {
|
||||
if args.MaxReconnectInterval == 0 {
|
||||
// Default interval
|
||||
// https://github.com/eclipse/paho.mqtt.golang/blob/master/options.go#L115
|
||||
args.MaxReconnectInterval = 10 * time.Minute
|
||||
}
|
||||
|
||||
if args.KeepAlive == 0 {
|
||||
args.KeepAlive = 10 * time.Second
|
||||
}
|
||||
|
||||
var store Store
|
||||
if args.QueueDir != "" {
|
||||
queueDir := filepath.Join(args.QueueDir, storePrefix+"-mqtt-"+id)
|
||||
target.store = NewQueueStore(queueDir, args.QueueLimit)
|
||||
if err := target.store.Open(); err != nil {
|
||||
target.loggerOnce(context.Background(), err, target.ID().String())
|
||||
return target, err
|
||||
store = NewQueueStore(queueDir, args.QueueLimit)
|
||||
if err := store.Open(); err != nil {
|
||||
return nil, fmt.Errorf("unable to initialize the queue store of MQTT `%s`: %w", id, err)
|
||||
}
|
||||
|
||||
if !test {
|
||||
go retryRegister()
|
||||
// Replays the events from the store.
|
||||
eventKeyCh := replayEvents(target.store, doneCh, target.loggerOnce, target.ID())
|
||||
// Start replaying events from the store.
|
||||
go sendEvents(target, eventKeyCh, doneCh, target.loggerOnce)
|
||||
}
|
||||
} else if token.Wait() && token.Error() != nil {
|
||||
return target, token.Error()
|
||||
}
|
||||
return target, nil
|
||||
|
||||
return &MQTTTarget{
|
||||
id: event.TargetID{ID: id, Name: "mqtt"},
|
||||
args: args,
|
||||
store: store,
|
||||
quitCh: make(chan struct{}),
|
||||
loggerOnce: loggerOnce,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user