81 lines
1.6 KiB
Go
81 lines
1.6 KiB
Go
package rmq
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"github.com/fox/fox/log"
|
|
amqp "github.com/rabbitmq/amqp091-go"
|
|
"time"
|
|
)
|
|
|
|
type Producer struct {
|
|
connection *Connection
|
|
config *RabbitMQConfig
|
|
}
|
|
|
|
func NewProducer(conn *Connection, config *RabbitMQConfig) *Producer {
|
|
return &Producer{
|
|
connection: conn,
|
|
config: config,
|
|
}
|
|
}
|
|
|
|
func (p *Producer) Publish(ctx context.Context, message string) error {
|
|
if !p.connection.IsConnected() {
|
|
return errors.New("not connected to RabbitMQ")
|
|
}
|
|
|
|
// 重试机制
|
|
for attempt := 1; attempt <= p.config.MaxRetries; attempt++ {
|
|
err := p.publishWithRetry(ctx, []byte(message))
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
log.WarnF("Publish attempt %d failed: %v", attempt, err)
|
|
if attempt < p.config.MaxRetries {
|
|
time.Sleep(time.Duration(attempt) * time.Second)
|
|
}
|
|
}
|
|
|
|
return errors.New("failed to publish message after all retries")
|
|
}
|
|
|
|
func (p *Producer) publishWithRetry(ctx context.Context, body []byte) error {
|
|
channel := p.connection.GetChannel()
|
|
|
|
err := channel.PublishWithContext(
|
|
ctx,
|
|
p.config.ExchangeName,
|
|
p.config.RoutingKey,
|
|
false,
|
|
false,
|
|
amqp.Publishing{
|
|
ContentType: "application/json",
|
|
Body: body,
|
|
DeliveryMode: amqp.Persistent,
|
|
Timestamp: time.Now(),
|
|
},
|
|
)
|
|
|
|
if err != nil {
|
|
return errors.Join(err, errors.New("failed to publish message"))
|
|
}
|
|
|
|
// 等待确认
|
|
select {
|
|
case confirm := <-p.connection.notifyConfirm:
|
|
if !confirm.Ack {
|
|
return errors.New("message not acknowledged by broker")
|
|
}
|
|
case <-time.After(5 * time.Second):
|
|
return errors.New("message confirmation timeout")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Producer) Close() error {
|
|
return p.connection.Close()
|
|
}
|