mirror of
https://github.com/eventials/goevents.git
synced 2025-04-26 13:48:59 +08:00
commit
f903bc0f7c
@ -24,7 +24,7 @@ type message struct {
|
|||||||
|
|
||||||
// producer holds a amqp connection and channel to publish messages to.
|
// producer holds a amqp connection and channel to publish messages to.
|
||||||
type producer struct {
|
type producer struct {
|
||||||
m sync.Mutex
|
m sync.RWMutex
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
conn *connection
|
conn *connection
|
||||||
channel *amqplib.Channel
|
channel *amqplib.Channel
|
||||||
@ -43,14 +43,16 @@ type producer struct {
|
|||||||
|
|
||||||
// ProducerConfig to be used when creating a new producer.
|
// ProducerConfig to be used when creating a new producer.
|
||||||
type ProducerConfig struct {
|
type ProducerConfig struct {
|
||||||
publishInterval time.Duration
|
PublishInterval time.Duration
|
||||||
|
ConfirmTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProducer returns a new AMQP Producer.
|
// NewProducer returns a new AMQP Producer.
|
||||||
// Uses a default ProducerConfig with 2 second of publish interval.
|
// Uses a default ProducerConfig with 2 second of publish interval.
|
||||||
func NewProducer(c messaging.Connection, exchange string) (*producer, error) {
|
func NewProducer(c messaging.Connection, exchange string) (*producer, error) {
|
||||||
return NewProducerConfig(c, exchange, ProducerConfig{
|
return NewProducerConfig(c, exchange, ProducerConfig{
|
||||||
publishInterval: 2 * time.Second,
|
PublishInterval: 2 * time.Second,
|
||||||
|
ConfirmTimeout: 10 * time.Second,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ func NewProducerConfig(c messaging.Connection, exchange string, config ProducerC
|
|||||||
producer := &producer{
|
producer := &producer{
|
||||||
conn: c.(*connection),
|
conn: c.(*connection),
|
||||||
config: config,
|
config: config,
|
||||||
internalQueue: make(chan message, 2),
|
internalQueue: make(chan message),
|
||||||
exchangeName: exchange,
|
exchangeName: exchange,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +97,15 @@ func (p *producer) Publish(action string, data []byte) {
|
|||||||
func (p *producer) publishAmqMessage(queue string, msg amqplib.Publishing) {
|
func (p *producer) publishAmqMessage(queue string, msg amqplib.Publishing) {
|
||||||
p.wg.Add(1)
|
p.wg.Add(1)
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"action": queue,
|
||||||
|
"message_id": msg.MessageId,
|
||||||
|
"type": "goevents",
|
||||||
|
"sub_type": "producer",
|
||||||
|
"exchange": p.exchangeName,
|
||||||
|
"length": len(p.internalQueue),
|
||||||
|
}).Debug("Publishing message to internal queue.")
|
||||||
|
|
||||||
p.internalQueue <- message{
|
p.internalQueue <- message{
|
||||||
action: queue,
|
action: queue,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
@ -119,6 +130,15 @@ func (p *producer) setClosed() {
|
|||||||
p.closed = true
|
p.closed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *producer) notifyProducerClosed() {
|
||||||
|
p.m.RLock()
|
||||||
|
defer p.m.RUnlock()
|
||||||
|
|
||||||
|
for _, c := range p.closes {
|
||||||
|
c <- true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Close the producer's internal queue.
|
// Close the producer's internal queue.
|
||||||
func (p *producer) Close() {
|
func (p *producer) Close() {
|
||||||
p.setClosed()
|
p.setClosed()
|
||||||
@ -129,9 +149,7 @@ func (p *producer) Close() {
|
|||||||
|
|
||||||
p.channel.Close()
|
p.channel.Close()
|
||||||
|
|
||||||
for _, c := range p.closes {
|
p.notifyProducerClosed()
|
||||||
c <- true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// changeChannel takes a new channel to the queue,
|
// changeChannel takes a new channel to the queue,
|
||||||
@ -208,8 +226,8 @@ func (p *producer) setChannelReady(ready bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *producer) isChannelReady() bool {
|
func (p *producer) isChannelReady() bool {
|
||||||
p.m.Lock()
|
p.m.RLock()
|
||||||
defer p.m.Unlock()
|
defer p.m.RUnlock()
|
||||||
|
|
||||||
return p.channelReady
|
return p.channelReady
|
||||||
}
|
}
|
||||||
@ -269,13 +287,16 @@ func (p *producer) publishMessage(msg amqplib.Publishing, queue string) (err err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
logMessage := log.WithFields(log.Fields{
|
||||||
"action": queue,
|
"action": queue,
|
||||||
"body": msg.Body,
|
|
||||||
"message_id": msg.MessageId,
|
"message_id": msg.MessageId,
|
||||||
"type": "goevents",
|
"type": "goevents",
|
||||||
"sub_type": "producer",
|
"sub_type": "producer",
|
||||||
"exchange": p.exchangeName,
|
"exchange": p.exchangeName,
|
||||||
|
})
|
||||||
|
|
||||||
|
logMessage.WithFields(log.Fields{
|
||||||
|
"body": msg.Body,
|
||||||
}).Debug("Publishing message to the exchange.")
|
}).Debug("Publishing message to the exchange.")
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -304,6 +325,8 @@ func (p *producer) publishMessage(msg amqplib.Publishing, queue string) (err err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logMessage.Debug("Waiting message to be acked or timed out.")
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case confirm := <-p.notifyConfirm:
|
case confirm := <-p.notifyConfirm:
|
||||||
if confirm.Ack {
|
if confirm.Ack {
|
||||||
@ -312,7 +335,7 @@ func (p *producer) publishMessage(msg amqplib.Publishing, queue string) (err err
|
|||||||
|
|
||||||
err = ErrNotAcked
|
err = ErrNotAcked
|
||||||
return
|
return
|
||||||
case <-time.After(p.config.publishInterval):
|
case <-time.After(p.config.ConfirmTimeout):
|
||||||
err = ErrTimedout
|
err = ErrTimedout
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -321,8 +344,8 @@ func (p *producer) publishMessage(msg amqplib.Publishing, queue string) (err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *producer) isClosed() bool {
|
func (p *producer) isClosed() bool {
|
||||||
p.m.Lock()
|
p.m.RLock()
|
||||||
defer p.m.Unlock()
|
defer p.m.RUnlock()
|
||||||
|
|
||||||
return p.closed
|
return p.closed
|
||||||
}
|
}
|
||||||
@ -345,7 +368,15 @@ func (p *producer) drainInternalQueue() {
|
|||||||
"sub_type": "producer",
|
"sub_type": "producer",
|
||||||
}).Error("Error publishing message to the exchange. Retrying...")
|
}).Error("Error publishing message to the exchange. Retrying...")
|
||||||
|
|
||||||
time.Sleep(p.config.publishInterval)
|
if err == ErrTimedout {
|
||||||
|
log.Warn("Closing producer channel due timeout wating msg confirmation")
|
||||||
|
|
||||||
|
// force close to run setupTopology
|
||||||
|
p.setChannelReady(false)
|
||||||
|
p.channel.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(p.config.PublishInterval)
|
||||||
} else {
|
} else {
|
||||||
p.wg.Done()
|
p.wg.Done()
|
||||||
retry = false
|
retry = false
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/eventials/goevents/amqp"
|
"github.com/eventials/goevents/amqp"
|
||||||
)
|
)
|
||||||
@ -58,14 +58,29 @@ func main() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
sigc := make(chan os.Signal, 1)
|
sigc := make(chan os.Signal, 1)
|
||||||
|
|
||||||
signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||||
|
|
||||||
fmt.Println("Waiting CTRL+C")
|
fmt.Println("Waiting CTRL+C")
|
||||||
|
|
||||||
<-sigc
|
<-sigc
|
||||||
|
|
||||||
|
closed := make(chan bool)
|
||||||
|
|
||||||
|
go func() {
|
||||||
fmt.Println("Closing producerA")
|
fmt.Println("Closing producerA")
|
||||||
producerA.Close()
|
producerA.Close()
|
||||||
|
|
||||||
fmt.Println("Closing producerB")
|
fmt.Println("Closing producerB")
|
||||||
producerB.Close()
|
producerB.Close()
|
||||||
|
|
||||||
|
closed <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-closed:
|
||||||
|
fmt.Println("Successfully closed.")
|
||||||
|
case <-time.After(20 * time.Second):
|
||||||
|
fmt.Println("Close timeout.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user