1
0
mirror of https://github.com/eventials/goevents.git synced 2025-04-24 13:48:53 +08:00
eventials.goevents/amqp/connection.go

161 lines
3.3 KiB
Go
Raw Normal View History

2016-12-01 10:52:22 -02:00
package amqp
import (
2017-03-09 17:32:05 -03:00
"sync"
"sync/atomic"
2017-03-09 17:32:05 -03:00
"time"
2017-07-17 10:14:51 -03:00
log "github.com/sirupsen/logrus"
2016-12-01 10:52:22 -02:00
amqplib "github.com/streadway/amqp"
2017-03-09 17:32:05 -03:00
"github.com/eventials/goevents/messaging"
2016-12-01 10:52:22 -02:00
)
2017-03-09 17:32:05 -03:00
// Connection with an AMQP peer.
2018-02-10 14:38:29 -02:00
type connection struct {
2017-03-09 17:32:05 -03:00
config ConnectionConfig
m sync.Mutex
url string
2016-12-01 10:52:22 -02:00
connection *amqplib.Connection
closed bool
connected int32
2017-03-09 17:32:05 -03:00
reestablishs []chan bool
}
// ConnectionConfig to be used when creating a new connection.
type ConnectionConfig struct {
2020-02-29 15:09:53 -03:00
ReconnectInterval time.Duration
2016-12-01 10:52:22 -02:00
}
2016-12-01 16:17:55 -02:00
// NewConnection returns an AMQP Connection.
// Uses a default ConnectionConfig with 2 second of reconnect interval.
2018-02-10 14:38:29 -02:00
func NewConnection(url string) (*connection, error) {
return NewConnectionConfig(url, ConnectionConfig{
2020-02-29 15:09:53 -03:00
ReconnectInterval: 2 * time.Second,
2017-03-09 17:32:05 -03:00
})
}
// NewConnectionConfig returns an AMQP Connection.
2018-02-10 14:38:29 -02:00
func NewConnectionConfig(url string, config ConnectionConfig) (*connection, error) {
connection := &connection{
2017-12-19 15:12:30 -02:00
url: url,
config: config,
}
err := connection.dial()
2016-12-01 10:52:22 -02:00
if err != nil {
return nil, err
}
atomic.StoreInt32(&connection.connected, 1)
2017-03-09 17:32:05 -03:00
go connection.handleConnectionClose()
return connection, nil
2016-12-01 10:52:22 -02:00
}
2017-03-09 17:32:05 -03:00
// NotifyConnectionClose returns a channel to notify when the connection closes.
2018-02-10 14:38:29 -02:00
func (c *connection) NotifyConnectionClose() <-chan error {
2016-12-28 10:20:09 -02:00
ch := make(chan error)
go func() {
2017-03-09 22:22:46 -03:00
ch <- <-c.connection.NotifyClose(make(chan *amqplib.Error))
2016-12-28 10:20:09 -02:00
}()
return ch
2016-12-28 09:20:29 -02:00
}
2017-03-09 17:32:05 -03:00
// NotifyReestablish returns a channel to notify when the connection is restablished.
2018-02-10 14:38:29 -02:00
func (c *connection) NotifyReestablish() <-chan bool {
receiver := make(chan bool, 1)
c.m.Lock()
2017-03-09 17:32:05 -03:00
c.reestablishs = append(c.reestablishs, receiver)
c.m.Unlock()
2017-03-09 17:32:05 -03:00
return receiver
}
2016-12-01 16:17:55 -02:00
// Consumer returns an AMQP Consumer.
2018-02-10 14:38:29 -02:00
func (c *connection) Consumer(autoAck bool, exchange, queue string) (messaging.Consumer, error) {
2016-12-28 09:20:29 -02:00
return NewConsumer(c, autoAck, exchange, queue)
2016-12-01 10:52:22 -02:00
}
// OpenChannel returns an AMQP Channel.
2018-02-10 14:38:29 -02:00
func (c *connection) openChannel() (*amqplib.Channel, error) {
2017-03-09 17:32:05 -03:00
c.m.Lock()
defer c.m.Unlock()
return c.connection.Channel()
}
2016-12-01 16:17:55 -02:00
// Producer returns an AMQP Producer.
2018-02-10 14:38:29 -02:00
func (c *connection) Producer(exchange string) (messaging.Producer, error) {
2017-03-09 17:32:05 -03:00
return NewProducer(c, exchange)
2016-12-01 10:52:22 -02:00
}
2016-12-01 16:17:55 -02:00
// Close closes the AMQP connection.
2018-02-10 14:38:29 -02:00
func (c *connection) Close() {
2017-03-09 17:32:05 -03:00
c.m.Lock()
defer c.m.Unlock()
if !c.closed {
c.closed = true
c.connection.Close()
}
2016-12-01 10:52:22 -02:00
}
2016-12-28 09:20:29 -02:00
2018-02-10 14:38:29 -02:00
func (c *connection) IsConnected() bool {
return atomic.LoadInt32(&c.connected) > 0
}
2018-02-10 14:38:29 -02:00
func (c *connection) dial() error {
2017-03-09 17:32:05 -03:00
conn, err := amqplib.Dial(c.url)
c.m.Lock()
c.connection = conn
c.m.Unlock()
2017-03-09 17:32:05 -03:00
return err
}
2018-02-10 14:38:29 -02:00
func (c *connection) handleConnectionClose() {
2017-03-09 17:32:05 -03:00
for !c.closed {
<-c.NotifyConnectionClose()
atomic.StoreInt32(&c.connected, 0)
2017-03-09 17:32:05 -03:00
for i := 0; !c.closed; i++ {
2017-12-19 15:12:30 -02:00
err := c.dial()
2017-03-09 17:32:05 -03:00
if err == nil {
atomic.StoreInt32(&c.connected, 1)
2017-12-19 15:12:30 -02:00
2017-03-09 17:32:05 -03:00
log.WithFields(log.Fields{
2017-05-24 18:23:07 -03:00
"type": "goevents",
"sub_type": "connection",
"attempt": i,
}).Info("Connection reestablished.")
2017-03-09 17:32:05 -03:00
for _, c := range c.reestablishs {
c <- true
}
break
} else {
log.WithFields(log.Fields{
2017-05-24 18:23:07 -03:00
"type": "goevents",
"sub_type": "connection",
"error": err,
"attempt": i,
}).Error("Error reestablishing connection. Retrying...")
2020-02-29 15:09:53 -03:00
time.Sleep(c.config.ReconnectInterval)
2017-03-09 17:32:05 -03:00
}
}
}
}