reconnect timer + fixes

This commit is contained in:
nquidox 2026-02-21 15:03:43 +03:00
parent 13ee3230e3
commit 42646a6a08
3 changed files with 71 additions and 21 deletions

View file

@ -5,21 +5,20 @@ import (
amqp "github.com/rabbitmq/amqp091-go" amqp "github.com/rabbitmq/amqp091-go"
"golang.org/x/time/rate" "golang.org/x/time/rate"
"log" "log"
"time"
) )
type Consumer interface { type Consumer interface {
Start() chan []byte Start(ctx context.Context, chanLen uint) chan []byte
} }
type consumeHandler struct { type consumeHandler struct {
ctx context.Context client *Client
client *Client
chanLen int
} }
func (c *consumeHandler) Start() chan []byte { func (c *consumeHandler) Start(ctx context.Context, chanLen uint) chan []byte {
msgCh := make(chan []byte, c.chanLen) msgCh := make(chan []byte, chanLen)
go runConsumer(c.ctx, c.client, msgCh) go runConsumer(ctx, c.client, msgCh)
return msgCh return msgCh
} }
@ -39,8 +38,20 @@ func runConsumer(ctx context.Context, client *Client, msgCh chan []byte) {
chClosedCh := make(chan *amqp.Error, 1) chClosedCh := make(chan *amqp.Error, 1)
client.Channel.NotifyClose(chClosedCh) client.Channel.NotifyClose(chClosedCh)
reconnectTimer := time.NewTimer(0)
defer reconnectTimer.Stop()
<-reconnectTimer.C
for { for {
if !reconnectTimer.Stop() {
select {
case <-reconnectTimer.C:
default:
}
}
select { select {
case <-runCtx.Done(): case <-runCtx.Done():
err = client.Close() err = client.Close()
if err != nil { if err != nil {
@ -49,25 +60,49 @@ func runConsumer(ctx context.Context, client *Client, msgCh chan []byte) {
return return
case amqErr := <-chClosedCh: case amqErr := <-chClosedCh:
log.Printf("AMQP Channel closed due to: %s\n", amqErr) log.Printf("AMQP Channel closed due to: %s Reconnecting...\n", amqErr)
reconnectTimer.Reset(time.Second)
case <-reconnectTimer.C:
deliveries, err = client.consume() deliveries, err = client.consume()
if err != nil { if err != nil {
log.Println("Error trying to consume, will try again") log.Println("Error trying to consume, will try again. Retry in 5 seconds.")
reconnectTimer.Reset(time.Second * 5)
continue continue
} }
chClosedCh = make(chan *amqp.Error, 1) chClosedCh = make(chan *amqp.Error, 1)
client.Channel.NotifyClose(chClosedCh) client.Channel.NotifyClose(chClosedCh)
case delivery := <-deliveries: case delivery, ok := <-deliveries:
msgCh <- delivery.Body if !ok {
log.Printf("Received message: %s\n", delivery.Body) log.Println("Deliveries channel closed unexpectedly")
reconnectTimer.Reset(time.Second)
if err = delivery.Ack(false); err != nil { continue
log.Printf("Error acknowledging message: %s\n", err) }
if err = limiter.Wait(runCtx); err != nil {
log.Printf("Wait limiter failed: %s\n", err)
}
select {
case <-runCtx.Done():
if err = delivery.Nack(false, true); err != nil {
log.Printf("Error nacking message: %s\n", err)
}
err = client.Close()
if err != nil {
log.Printf("Close failed: %s\n", err)
}
return
case msgCh <- delivery.Body:
log.Printf("Received message: %s\n", delivery.Body)
if err = delivery.Ack(false); err != nil {
log.Printf("Error acknowledging message: %s\n", err)
}
} }
limiter.Wait(runCtx)
} }
} }
} }

View file

@ -1,7 +1,6 @@
package rabbit package rabbit
import ( import (
"context"
amqp "github.com/rabbitmq/amqp091-go" amqp "github.com/rabbitmq/amqp091-go"
"log" "log"
"os" "os"
@ -68,6 +67,6 @@ func NewPublisher(client *Client) Publisher {
return &pubHandler{client: client} return &pubHandler{client: client}
} }
func NewConsumer(ctx context.Context, client *Client, chanLen int) Consumer { func NewConsumer(client *Client) Consumer {
return &consumeHandler{ctx: ctx, client: client, chanLen: chanLen} return &consumeHandler{client: client}
} }

View file

@ -2,18 +2,34 @@ package rabbit
import ( import (
"errors" "errors"
"log"
"time" "time"
) )
type Publisher interface { type Publisher interface {
Push(data []byte) error Start(chanLen uint) <-chan []byte
} }
type pubHandler struct { type pubHandler struct {
client *Client client *Client
} }
func (p *pubHandler) Push(data []byte) error { func (p *pubHandler) Start(chanLen uint) <-chan []byte {
ch := make(chan []byte, chanLen)
go func() {
for {
select {
case msg := <-ch:
if err := p.push(msg); err != nil {
log.Printf("Error publishing message: %s", err)
}
}
}
}()
return ch
}
func (p *pubHandler) push(data []byte) error {
p.client.mutex.Lock() p.client.mutex.Lock()
if !p.client.isReady { if !p.client.isReady {
p.client.mutex.Unlock() p.client.mutex.Unlock()