@@ -2,6 +2,7 @@ package main
22
33import (
44 "context"
5+ "errors"
56 "fmt"
67 "github.com/Azure/go-amqp"
78 "github.com/rabbitmq/rabbitmq-amqp-go-client/pkg/rabbitmq_amqp"
@@ -14,6 +15,7 @@ func main() {
1415 var stateAccepted int32
1516 var stateReleased int32
1617 var stateRejected int32
18+
1719 var received int32
1820 var failed int32
1921
@@ -40,6 +42,12 @@ func main() {
4042 amqpConnection , err := rabbitmq_amqp .Dial (context .Background (), []string {"amqp://" }, & rabbitmq_amqp.AmqpConnOptions {
4143 SASLType : amqp .SASLTypeAnonymous (),
4244 ContainerID : "reliable-amqp10-go" ,
45+ RecoveryConfiguration : & rabbitmq_amqp.RecoveryConfiguration {
46+ ActiveRecovery : true ,
47+ BackOffReconnectInterval : 2 * time .Second , // we reduce the reconnect interval to speed up the test. The default is 5 seconds
48+ // In production, you should avoid BackOffReconnectInterval with low values since it can cause a high number of reconnection attempts
49+ MaxReconnectAttempts : 5 ,
50+ },
4351 })
4452 if err != nil {
4553 rabbitmq_amqp .Error ("Error opening connection" , err )
@@ -62,40 +70,45 @@ func main() {
6270 return
6371 }
6472
65- //consumer, err := amqpConnection.NewConsumer(context.Background(), &rabbitmq_amqp.QueueAddress{
66- // Queue: queueName,
67- //}, "reliable-consumer")
68- //if err != nil {
69- // rabbitmq_amqp.Error("Error creating consumer", err)
70- // return
71- //}
72-
73- //consumerContext, cancel := context.WithCancel(context.Background())
74-
75- //// Consume messages from the queue
76- //go func(ctx context.Context) {
77- // for {
78- // deliveryContext, err := consumer.Receive(ctx)
79- // if errors.Is(err, context.Canceled) {
80- // // The consumer was closed correctly
81- // return
82- // }
83- // if err != nil {
84- // // An error occurred receiving the message
85- // rabbitmq_amqp.Error("[Consumer]", "Error receiving message", err)
86- // return
87- // }
88- //
89- // rabbitmq_amqp.Info("[Consumer]", "Received message",
90- // fmt.Sprintf("%s", deliveryContext.Message().Data))
91- //
92- // err = deliveryContext.Accept(context.Background())
93- // if err != nil {
94- // rabbitmq_amqp.Error("Error accepting message", err)
95- // return
96- // }
97- // }
98- //}(consumerContext)
73+ consumer , err := amqpConnection .NewConsumer (context .Background (), & rabbitmq_amqp.QueueAddress {
74+ Queue : queueName ,
75+ }, "reliable-consumer" )
76+ if err != nil {
77+ rabbitmq_amqp .Error ("Error creating consumer" , err )
78+ return
79+ }
80+
81+ consumerContext , cancel := context .WithCancel (context .Background ())
82+
83+ // Consume messages from the queue
84+ go func (ctx context.Context ) {
85+ for {
86+ deliveryContext , err := consumer .Receive (ctx )
87+ if errors .Is (err , context .Canceled ) {
88+ // The consumer was closed correctly
89+ return
90+ }
91+ if err != nil {
92+ // An error occurred receiving the message
93+ rabbitmq_amqp .Error ("[NewConsumer]" , "Error receiving message, retry in 2_500 ms" , err , "queue" , queueName )
94+ // here the consumer could be disconnected from the server due to a network error
95+ // in this specific case, we just wait for 2_500 ms and try again (2 seconds is the reconnect interval we defined + random 500 random ms)
96+ // while the connection is reestablished
97+ // you can use the stateChanged channel to be notified when the connection is reestablished
98+ time .Sleep (2500 * time .Millisecond )
99+ continue
100+ }
101+
102+ atomic .AddInt32 (& received , 1 )
103+ err = deliveryContext .Accept (context .Background ())
104+ if err != nil {
105+ // same here the delivery could not be accepted due to a network error
106+ // we wait for 2_500 ms and try again
107+ time .Sleep (2500 * time .Millisecond )
108+ continue
109+ }
110+ }
111+ }(consumerContext )
99112
100113 publisher , err := amqpConnection .NewPublisher (context .Background (), & rabbitmq_amqp.QueueAddress {
101114 Queue : queueName ,
@@ -106,12 +119,16 @@ func main() {
106119 }
107120
108121 for i := 0 ; i < 1_000_000 ; i ++ {
109- // Publish a message to the exchange
110122 publishResult , err := publisher .Publish (context .Background (), amqp .NewMessage ([]byte ("Hello, World!" + fmt .Sprintf ("%d" , i ))))
111123 if err != nil {
112124 rabbitmq_amqp .Error ("Error publishing message" , "error" , err )
125+ // here you need to deal with the error. You can store the message in a local in memory/persistent storage
126+ // then retry to send the message as soon as the connection is reestablished
127+ // in this specific case, we just wait for 2_500 ms and try again (2 seconds is the reconnect interval we defined + random 500 random ms)
128+ // you can use the stateChanged channel to be notified when the connection is reestablished
129+ // and use some signal to reactivate the message sending
113130 atomic .AddInt32 (& failed , 1 )
114- time .Sleep (1 * time .Second )
131+ time .Sleep (2500 * time .Millisecond )
115132 continue
116133 }
117134 switch publishResult .Outcome .(type ) {
@@ -136,17 +153,17 @@ func main() {
136153 var input string
137154 _ , _ = fmt .Scanln (& input )
138155
139- // cancel()
156+ cancel ()
140157 //Close the consumer
141- // err = consumer.Close(context.Background())
142- // if err != nil {
143- // rabbitmq_amqp.Error("[Consumer ]", err)
144- // return
145- // }
158+ err = consumer .Close (context .Background ())
159+ if err != nil {
160+ rabbitmq_amqp .Error ("[NewConsumer ]" , err )
161+ return
162+ }
146163 // Close the publisher
147164 err = publisher .Close (context .Background ())
148165 if err != nil {
149- rabbitmq_amqp .Error ("[Publisher ]" , err )
166+ rabbitmq_amqp .Error ("[NewPublisher ]" , err )
150167 return
151168 }
152169
0 commit comments