package rmq import ( "context" "github.com/fox/fox/log" "github.com/pkg/errors" 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.Wrap(err, "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() }