github.com/fredmanre/go-rabbitmq-client@v1.0.7/go-rabbitmq/client.go (about) 1 package rabbit 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "time" 7 8 amqp "github.com/rabbitmq/amqp091-go" 9 ) 10 11 // RabbitMQClient contains the basic objects for a AMQ connection 12 type RabbitMQClient struct { 13 Connection *amqp.Connection 14 Channel *amqp.Channel 15 Reception struct { 16 Queue amqp.Queue 17 } 18 Dispatch struct{} 19 Err chan error 20 } 21 22 // RabbitConnection Reconnection config 23 type RabbitConnection struct { 24 username string 25 password string 26 host string 27 port int `default:"5672"` 28 ReconnectionTimeout int `default:"5"` 29 SetupQueue RabbitSetupQueue 30 } 31 32 // RabbitSetupQueue Queue config 33 type RabbitSetupQueue struct { 34 exchange string 35 queueName string 36 autoDelete bool 37 routingKeys []string 38 queueIsDurable bool 39 } 40 41 var RbConn RabbitConnection 42 43 // InitMeConn rabbit params - RabbitParameters 44 func (rbp *RabbitConnection) InitMeConn(username, password, host string, port int) { 45 rbp.username, rbp.password, rbp.host, rbp.port = username, password, host, port 46 } 47 48 // InitMeSetupQueue Rabbit SetUp queue configuration for reconnection 49 func (rbp *RabbitConnection) InitMeSetupQueue(exchange, queueName string, autoDelete, isDurable bool, routingKeys []string) { 50 rbp.SetupQueue.exchange, rbp.SetupQueue.queueName = exchange, queueName 51 rbp.SetupQueue.autoDelete, rbp.SetupQueue.queueIsDurable, rbp.SetupQueue.routingKeys = autoDelete, isDurable, routingKeys 52 } 53 54 // GetQueueName RabbitMQClient_GetQueueName return the queue name for a receiver 55 func (a *RabbitMQClient) GetQueueName() string { 56 return a.Reception.Queue.Name 57 } 58 59 // StartConnection RabbitMQClient_StartConnection Starts the connection with rabbitMQ server. 60 // Dials up and creates a channel 61 func (a *RabbitMQClient) StartConnection(username, password, host string, port int) error { 62 63 a.Err = make(chan error) 64 RbConn.InitMeConn(username, password, host, port) 65 url := fmt.Sprintf("amqp://%s:%s@%s:%d/", username, password, host, port) 66 conn, err := amqp.Dial(url) 67 if err != nil { 68 return fmt.Errorf("amqp dial failure: %s", err) 69 } 70 71 a.Connection = conn 72 // we declare a channel to be used for the reconnection process 73 go func() { 74 closeErr := <-a.Connection.NotifyClose(make(chan *amqp.Error)) // we listen to notify if the connection is closed 75 a.Err <- fmt.Errorf("disconnected from rabbitMQ: %s", closeErr) 76 }() 77 78 errCh := a.CreateChannel() 79 if errCh != nil { 80 return fmt.Errorf("Couldn't create a channel in start connection err: %s", errCh) 81 } 82 return nil 83 } 84 85 // CreateChannel RabbitMQClient_CreateChannel creates a channel and saves it in struct 86 func (a *RabbitMQClient) CreateChannel() error { 87 ch, err := a.Connection.Channel() 88 if err != nil { 89 return fmt.Errorf("channel creating failure: %s", err) 90 } 91 a.Channel = ch 92 return nil 93 } 94 95 // Reconnect Manage reconnection to rabbitMQ 96 // for startConnection: username, password, host & port 97 // for SetupQueues: queueName, queueIsDurable, autoDelete, routingKeys, exchange 98 func (a *RabbitMQClient) Reconnect() error { 99 100 time.Sleep(time.Duration(RbConn.ReconnectionTimeout)) 101 fmt.Println("Recconnecting with params ", RbConn) 102 RbConn.ReconnectionTimeout += 5 103 if err := a.StartConnection(RbConn.username, RbConn.password, RbConn.host, RbConn.port); err != nil { 104 return err 105 } 106 if err := a.SetupQueues( 107 RbConn.SetupQueue.queueName, RbConn.SetupQueue.queueIsDurable, 108 RbConn.SetupQueue.autoDelete, RbConn.SetupQueue.routingKeys, 109 RbConn.SetupQueue.exchange); err != nil { 110 return err 111 } 112 return nil 113 114 } 115 116 // SetupQueues RabbitMQClient_SetupQueues Declares and binds a queue to an exchange 117 func (a *RabbitMQClient) SetupQueues(queueName string, queueIsDurable, autoDelete bool, routingKeys []string, exchange string) error { 118 q, err := a.Channel.QueueDeclare( 119 queueName, // name 120 queueIsDurable, // durable 121 autoDelete, // delete when un used 122 false, // exclusive 123 false, // no-wait 124 nil, // arguments 125 ) 126 if err != nil { 127 return fmt.Errorf("failed to declare a queue with name: %s, err: %s", queueName, err) 128 } 129 RbConn.InitMeSetupQueue(exchange, queueName, autoDelete, queueIsDurable, routingKeys) // params for reconnection queue 130 for _, key := range routingKeys { 131 errBind := a.Channel.QueueBind(queueName, key, exchange, false, nil) 132 if errBind != nil { 133 return fmt.Errorf("failed to Bind a queue err: %s", errBind) 134 } 135 } 136 137 a.Reception.Queue = q 138 return nil 139 } 140 141 // StartReceiver RabbitMQClient_StartReceiver Starts a rabbit MQ receiver with the passed configuration, returns a channel 142 // that will receive the messages, along with the connection and channel instance 143 func (a *RabbitMQClient) StartReceiver(queueName string, isDurable, autoDelete bool, routingKeys []string, exchanges interface{}, consumerTag string) (<-chan amqp.Delivery, error) { 144 switch exchangeData := exchanges.(type) { 145 case []string: 146 for _, exchange := range exchangeData { 147 err := a.SetupQueues( 148 queueName, isDurable, autoDelete, routingKeys, exchange, 149 ) 150 if err != nil { 151 return make(chan amqp.Delivery), fmt.Errorf("failed to setup queue err: %s", err) 152 } 153 } 154 case string: 155 err := a.SetupQueues( 156 queueName, isDurable, autoDelete, routingKeys, exchangeData, 157 ) 158 if err != nil { 159 return make(chan amqp.Delivery), fmt.Errorf("failed to setup queue err: %s", err) 160 } 161 162 default: 163 return make(chan amqp.Delivery), fmt.Errorf("failed to declare exchange due to wrong type in var %v", exchanges) 164 } 165 messages, err := a.Channel.Consume( 166 queueName, // queue 167 consumerTag, // consumer 168 true, // auto-ack 169 false, // exclusive 170 false, // no-local 171 false, // no-wait 172 nil, // args 173 ) 174 if err != nil { 175 return make(chan amqp.Delivery), fmt.Errorf("failed to register a consumer: %s", err) 176 } 177 return messages, nil 178 } 179 180 // SetupDispatcher RabbitMQClient_SetupDispatcher Declares the exchanges to be used to deliver messages 181 func (a *RabbitMQClient) SetupDispatcher(exchange, exchangeType string, isDurable, autoDelete bool) error { 182 if err := a.Channel.ExchangeDeclare( 183 exchange, // name 184 exchangeType, // type 185 isDurable, // durable 186 autoDelete, // auto-deleted 187 false, // internal 188 false, // noWait 189 nil, // arguments 190 ); err != nil { 191 return fmt.Errorf("exchange declare: %s", err) 192 } 193 return nil 194 } 195 196 // SendMessage RabbitMQClient_SendMessage Deliver the message to the specified exchange, if exchange not created this will 197 // throw an error 198 func (a *RabbitMQClient) SendMessage(exchange, routingKey string, message interface{}) error { 199 // non blocking channel - if there is no error will go to default where we do nothing 200 select { 201 case err := <-a.Err: 202 if err != nil { 203 a.Reconnect() 204 } 205 default: 206 } 207 208 messageBody, err := json.Marshal(message) 209 if err != nil { 210 return fmt.Errorf("couldn't marshal the map to an slice of bytes") 211 } 212 213 if err = a.Channel.Publish( 214 exchange, // publish to an exchange 215 routingKey, // routing to 0 or more queues 216 false, // mandatory 217 false, // immediate 218 amqp.Publishing{ 219 Headers: amqp.Table{}, 220 ContentType: "text/plain", 221 ContentEncoding: "", 222 Body: messageBody, 223 DeliveryMode: amqp.Transient, // 1=non-persistent, 2=persistent 224 Priority: 0, // 0-9 225 }, 226 ); err != nil { 227 return fmt.Errorf("exchange publish: %s", err) 228 } 229 return nil 230 }