├── rabbit-mq └── rabbitmq.conf ├── consumer ├── .env.sample ├── consts │ └── consts.go ├── Dockerfile ├── handlers │ └── example.go ├── main.go ├── utils │ ├── config.go │ ├── logger.go │ └── rmq_consumer.go ├── go.mod └── go.sum ├── producer ├── models │ └── message.go ├── consts │ └── consts.go ├── .env.sample ├── Dockerfile ├── controllers │ ├── ping.go │ └── example.go ├── .gitignore ├── middlewares │ ├── request_id.go │ ├── cors.go │ └── request_logger.go ├── routers │ └── setup.go ├── utils │ ├── config.go │ ├── logger.go │ └── rmq_publisher.go ├── app │ └── setup_app.go ├── main.go ├── go.mod └── go.sum ├── .gitignore ├── LICENSE ├── docker-compose.yaml └── readme.md /rabbit-mq/rabbitmq.conf: -------------------------------------------------------------------------------- 1 | listeners.tcp.default = 5673 -------------------------------------------------------------------------------- /consumer/.env.sample: -------------------------------------------------------------------------------- 1 | LOG_LEVEL = debug 2 | RMQ_URL = amqp://guest:guest@localhost:5000/ -------------------------------------------------------------------------------- /producer/models/message.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Message struct { 4 | Message string `json:"message" binding:"required"` 5 | } 6 | -------------------------------------------------------------------------------- /consumer/consts/consts.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ENV_FILE = ".env" 4 | const ENV_FILE_DIRECTORY = "." 5 | 6 | const EXAMPLE_QUEUE = "example" 7 | -------------------------------------------------------------------------------- /producer/consts/consts.go: -------------------------------------------------------------------------------- 1 | package consts 2 | 3 | const ENV_FILE = ".env" 4 | const ENV_FILE_DIRECTORY = "." 5 | 6 | const EXAMPLE_QUEUE = "example" 7 | -------------------------------------------------------------------------------- /producer/.env.sample: -------------------------------------------------------------------------------- 1 | GIN_MODE = release 2 | LOG_LEVEL = debug 3 | GIN_ADDR = 0.0.0.0 4 | GIN_PORT = 6000 5 | GIN_HTTPS = false 6 | RMQ_URL = amqp://guest:guest@localhost:5000/ 7 | -------------------------------------------------------------------------------- /consumer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest 2 | 3 | ENV APP_NAME rmq-consumer 4 | 5 | COPY . /go/src/${APP_NAME} 6 | WORKDIR /go/src/${APP_NAME} 7 | 8 | RUN go get ./ 9 | RUN go build -o ${APP_NAME} 10 | 11 | CMD ./${APP_NAME} -------------------------------------------------------------------------------- /producer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest 2 | 3 | ENV APP_NAME rmq-producer 4 | 5 | COPY . /go/src/${APP_NAME} 6 | WORKDIR /go/src/${APP_NAME} 7 | 8 | RUN go get ./ 9 | RUN go build -o ${APP_NAME} 10 | 11 | CMD ./${APP_NAME} -------------------------------------------------------------------------------- /producer/controllers/ping.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | func Ping(c *gin.Context) { 10 | c.JSON(http.StatusOK, gin.H{ 11 | "message": "pong", 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /consumer/handlers/example.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "github.com/rs/zerolog/log" 5 | "github.com/streadway/amqp" 6 | ) 7 | 8 | func HandleExample(queue string, msg amqp.Delivery, err error) { 9 | if err != nil { 10 | log.Err(err).Msg("Error occurred in RMQ consumer") 11 | } 12 | log.Info().Msgf("Message received on '%s' queue: %s", queue, string(msg.Body)) 13 | } 14 | -------------------------------------------------------------------------------- /producer/.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | .env 9 | .dockerignore 10 | .vscode 11 | 12 | # Test binary, built with `go test -c` 13 | *.test 14 | 15 | # Output of the go coverage tool, specifically when used with LiteIDE 16 | *.out 17 | 18 | # Dependency directories (remove the comment below to include it) 19 | # vendor/ 20 | -------------------------------------------------------------------------------- /producer/middlewares/request_id.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/google/uuid" 6 | ) 7 | 8 | // Request ID middleware 9 | func RequestID() gin.HandlerFunc { 10 | return func(c *gin.Context) { 11 | // Generate UUID 12 | id := uuid.New().String() 13 | // Set context variable 14 | c.Set("x-request-id", id) 15 | // Set header 16 | c.Header("x-request-id", id) 17 | c.Next() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /producer/routers/setup.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/lakhinsu/rabbitmq-go-example/producer/controllers" 6 | ) 7 | 8 | // Function to setup routers and router groups 9 | func SetupRouters(app *gin.Engine) { 10 | v1 := app.Group("/v1") 11 | { 12 | v1.GET("/ping", controllers.Ping) 13 | v1.POST("/publish/example", controllers.Example) 14 | } 15 | // Standalone route example 16 | // app.GET("/ping", controllers.Ping) 17 | } 18 | -------------------------------------------------------------------------------- /consumer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lakhinsu/rabbitmq-go-example/consumer/consts" 5 | "github.com/lakhinsu/rabbitmq-go-example/consumer/handlers" 6 | "github.com/lakhinsu/rabbitmq-go-example/consumer/utils" 7 | ) 8 | 9 | func main() { 10 | connectionString := utils.GetEnvVar("RMQ_URL") 11 | 12 | exampleQueue := utils.RMQConsumer{ 13 | consts.EXAMPLE_QUEUE, 14 | connectionString, 15 | handlers.HandleExample, 16 | } 17 | // Start consuming message on the specified queues 18 | forever := make(chan bool) 19 | 20 | go exampleQueue.Consume() 21 | 22 | // Multiple listeners can be specified here 23 | 24 | <-forever 25 | } 26 | -------------------------------------------------------------------------------- /producer/middlewares/cors.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | ) 6 | 7 | // CORS (Cross-Origin Resource Sharing) 8 | // CORS middleware is always very specific to use case, 9 | // so adding very minimal placeholder here 10 | func CORSMiddleware() gin.HandlerFunc { 11 | return func(c *gin.Context) { 12 | c.Writer.Header().Set("Access-Control-Allow-Origin", "*") 13 | c.Writer.Header().Set("Access-Control-Max-Age", "600") 14 | c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET") 15 | c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length") 16 | c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") 17 | 18 | if c.Request.Method == "OPTIONS" { 19 | c.AbortWithStatus(200) 20 | } else { 21 | c.Next() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /producer/middlewares/request_logger.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/rs/zerolog/log" 8 | ) 9 | 10 | // Request logging middleware 11 | func RequestLogger() gin.HandlerFunc { 12 | return func(c *gin.Context) { 13 | request_id := c.GetString("x-request-id") 14 | client_ip := c.ClientIP() 15 | user_agent := c.Request.UserAgent() 16 | method := c.Request.Method 17 | path := c.Request.URL.Path 18 | 19 | t := time.Now() 20 | 21 | c.Next() 22 | 23 | latency := float32(time.Since(t).Seconds()) 24 | 25 | status := c.Writer.Status() 26 | log.Info().Str("request_id", request_id).Str("client_ip", client_ip). 27 | Str("user_agent", user_agent).Str("method", method).Str("path", path). 28 | Float32("latency", latency).Int("status", status).Msg("") 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /consumer/utils/config.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/lakhinsu/rabbitmq-go-example/consumer/consts" 5 | "github.com/rs/zerolog/log" 6 | "github.com/spf13/viper" 7 | ) 8 | 9 | func init() { 10 | viper.SetConfigFile(consts.ENV_FILE) 11 | viper.AddConfigPath(consts.ENV_FILE_DIRECTORY) 12 | err := viper.ReadInConfig() 13 | if err != nil { 14 | log.Debug().Err(err). 15 | Msg("Error occurred while reading env file, might fallback to OS env config") 16 | } 17 | viper.AutomaticEnv() 18 | } 19 | 20 | // This function can be used to get ENV Var in our App 21 | // Modify this if you change the library to read ENV 22 | func GetEnvVar(name string) string { 23 | if !viper.IsSet(name) { 24 | log.Debug().Msgf("Environment variable %s is not set", name) 25 | return "" 26 | } 27 | value := viper.GetString(name) 28 | return value 29 | } 30 | -------------------------------------------------------------------------------- /producer/utils/config.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/lakhinsu/rabbitmq-go-example/producer/consts" 5 | "github.com/rs/zerolog/log" 6 | "github.com/spf13/viper" 7 | ) 8 | 9 | func init() { 10 | viper.SetConfigFile(consts.ENV_FILE) 11 | viper.AddConfigPath(consts.ENV_FILE_DIRECTORY) 12 | err := viper.ReadInConfig() 13 | if err != nil { 14 | log.Debug().Err(err). 15 | Msg("Error occurred while reading env file, might fallback to OS env config") 16 | } 17 | viper.AutomaticEnv() 18 | } 19 | 20 | // This function can be used to get ENV Var in our App 21 | // Modify this if you change the library to read ENV 22 | func GetEnvVar(name string) string { 23 | if !viper.IsSet(name) { 24 | log.Debug().Msgf("Environment variable %s is not set", name) 25 | return "" 26 | } 27 | value := viper.GetString(name) 28 | return value 29 | } 30 | -------------------------------------------------------------------------------- /producer/app/setup_app.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/lakhinsu/rabbitmq-go-example/producer/middlewares" 6 | "github.com/lakhinsu/rabbitmq-go-example/producer/routers" 7 | "github.com/rs/zerolog/log" 8 | ) 9 | 10 | // Function to setup the app object 11 | func SetupApp() *gin.Engine { 12 | log.Info().Msg("Initializing service") 13 | 14 | // Create barebone engine 15 | app := gin.New() 16 | // Add default recovery middleware 17 | app.Use(gin.Recovery()) 18 | 19 | // disabling the trusted proxy feature 20 | app.SetTrustedProxies(nil) 21 | 22 | // Add cors, request ID and request logging middleware 23 | log.Info().Msg("Adding cors, request id and request logging middleware") 24 | app.Use(middlewares.CORSMiddleware(), middlewares.RequestID(), middlewares.RequestLogger()) 25 | 26 | // Setup routers 27 | log.Info().Msg("Setting up routers") 28 | routers.SetupRouters(app) 29 | 30 | return app 31 | } 32 | -------------------------------------------------------------------------------- /consumer/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lakhinsu/rabbitmq-go-example/consumer 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/fsnotify/fsnotify v1.5.1 // indirect 7 | github.com/hashicorp/hcl v1.0.0 // indirect 8 | github.com/magiconair/properties v1.8.5 // indirect 9 | github.com/mitchellh/mapstructure v1.4.3 // indirect 10 | github.com/pelletier/go-toml v1.9.4 // indirect 11 | github.com/rs/zerolog v1.26.1 // indirect 12 | github.com/spf13/afero v1.6.0 // indirect 13 | github.com/spf13/cast v1.4.1 // indirect 14 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 15 | github.com/spf13/pflag v1.0.5 // indirect 16 | github.com/spf13/viper v1.10.1 // indirect 17 | github.com/streadway/amqp v1.0.0 // indirect 18 | github.com/subosito/gotenv v1.2.0 // indirect 19 | golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect 20 | golang.org/x/text v0.3.7 // indirect 21 | gopkg.in/ini.v1 v1.66.2 // indirect 22 | gopkg.in/yaml.v2 v2.4.0 // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /consumer/utils/logger.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/rs/zerolog" 7 | "github.com/rs/zerolog/log" 8 | ) 9 | 10 | // Modify the init function if you change logging library 11 | // Find and replace the imports in the rest of the app 12 | func init() { 13 | // Read log level 14 | logLevel := GetEnvVar("LOG_LEVEL") 15 | 16 | // Replace with switch or add more levels as per need 17 | if logLevel == "debug" { 18 | zerolog.SetGlobalLevel(zerolog.DebugLevel) 19 | } else { 20 | zerolog.SetGlobalLevel(zerolog.InfoLevel) 21 | } 22 | 23 | // Set time format 24 | zerolog.TimeFieldFormat = zerolog.TimeFormatUnix 25 | 26 | // Set Global fields 27 | host, err := os.Hostname() 28 | if err != nil { 29 | log.Logger = log.With().Str("host", "unknown").Logger() 30 | } else { 31 | log.Logger = log.With().Str("host", host).Logger() 32 | } 33 | 34 | log.Logger = log.With().Str("service", "rabbitmq-consumer").Logger() 35 | 36 | log.Logger = log.With().Caller().Logger() 37 | } 38 | -------------------------------------------------------------------------------- /producer/utils/logger.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/rs/zerolog" 7 | "github.com/rs/zerolog/log" 8 | ) 9 | 10 | // Modify the init function if you change logging library 11 | // Find and replace the imports in the rest of the app 12 | func init() { 13 | // Read log level 14 | logLevel := GetEnvVar("LOG_LEVEL") 15 | 16 | // Replace with switch or add more levels as per need 17 | if logLevel == "debug" { 18 | zerolog.SetGlobalLevel(zerolog.DebugLevel) 19 | } else { 20 | zerolog.SetGlobalLevel(zerolog.InfoLevel) 21 | } 22 | 23 | // Set time format 24 | zerolog.TimeFieldFormat = zerolog.TimeFormatUnix 25 | 26 | // Set Global fields 27 | host, err := os.Hostname() 28 | if err != nil { 29 | log.Logger = log.With().Str("host", "unknown").Logger() 30 | } else { 31 | log.Logger = log.With().Str("host", host).Logger() 32 | } 33 | 34 | log.Logger = log.With().Str("service", "rabbitmq-producer").Logger() 35 | 36 | log.Logger = log.With().Caller().Logger() 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 lakhinsu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /producer/controllers/example.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/lakhinsu/rabbitmq-go-example/producer/consts" 8 | "github.com/lakhinsu/rabbitmq-go-example/producer/models" 9 | "github.com/lakhinsu/rabbitmq-go-example/producer/utils" 10 | "github.com/rs/zerolog/log" 11 | ) 12 | 13 | func Example(c *gin.Context) { 14 | var msg models.Message 15 | 16 | request_id := c.GetString("x-request-id") 17 | 18 | // Bind request payload with our model 19 | if binderr := c.ShouldBindJSON(&msg); binderr != nil { 20 | 21 | log.Error().Err(binderr).Str("request_id", request_id). 22 | Msg("Error occurred while binding request data") 23 | 24 | c.JSON(http.StatusUnprocessableEntity, gin.H{ 25 | "message": binderr.Error(), 26 | }) 27 | return 28 | } 29 | 30 | connectionString := utils.GetEnvVar("RMQ_URL") 31 | 32 | rmqProducer := utils.RMQProducer{ 33 | consts.EXAMPLE_QUEUE, 34 | connectionString, 35 | } 36 | 37 | rmqProducer.PublishMessage("text/plain", []byte(msg.Message)) 38 | 39 | c.JSON(http.StatusOK, gin.H{ 40 | "response": "Message received", 41 | }) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /producer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/gin-gonic/gin" 7 | "github.com/lakhinsu/rabbitmq-go-example/producer/app" 8 | "github.com/lakhinsu/rabbitmq-go-example/producer/utils" 9 | "github.com/rs/zerolog/log" 10 | ) 11 | 12 | func init() { 13 | // Set gin mode 14 | mode := utils.GetEnvVar("GIN_MODE") 15 | gin.SetMode(mode) 16 | } 17 | 18 | func main() { 19 | // Setup the app 20 | app := app.SetupApp() 21 | 22 | // Read ADDR and port 23 | addr := utils.GetEnvVar("GIN_ADDR") 24 | port := utils.GetEnvVar("GIN_PORT") 25 | 26 | https := utils.GetEnvVar("GIN_HTTPS") 27 | // HTTPS mode 28 | if https == "true" { 29 | certFile := utils.GetEnvVar("GIN_CERT") 30 | certKey := utils.GetEnvVar("GIN_CERT_KEY") 31 | log.Info().Msgf("Starting service on https//:%s:%s", addr, port) 32 | 33 | if err := app.RunTLS(fmt.Sprintf("%s:%s", addr, port), certFile, certKey); err != nil { 34 | log.Fatal().Err(err).Msg("Error occurred while setting up the server in HTTPS mode") 35 | } 36 | } 37 | // HTTP mode 38 | log.Info().Msgf("Starting service on http//:%s:%s", addr, port) 39 | if err := app.Run(fmt.Sprintf("%s:%s", addr, port)); err != nil { 40 | log.Fatal().Err(err).Msg("Error occurred while setting up the server") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /producer/utils/rmq_publisher.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/rs/zerolog/log" 5 | 6 | "github.com/streadway/amqp" 7 | ) 8 | 9 | type RMQProducer struct { 10 | Queue string 11 | ConnectionString string 12 | } 13 | 14 | func (x RMQProducer) OnError(err error, msg string) { 15 | if err != nil { 16 | log.Err(err).Msgf("Error occurred while publishing message on '%s' queue. Error message: %s", x.Queue, msg) 17 | } 18 | } 19 | 20 | func (x RMQProducer) PublishMessage(contentType string, body []byte) { 21 | conn, err := amqp.Dial(x.ConnectionString) 22 | x.OnError(err, "Failed to connect to RabbitMQ") 23 | defer conn.Close() 24 | 25 | ch, err := conn.Channel() 26 | x.OnError(err, "Failed to open a channel") 27 | defer ch.Close() 28 | 29 | q, err := ch.QueueDeclare( 30 | x.Queue, // name 31 | false, // durable 32 | false, // delete when unused 33 | false, // exclusive 34 | false, // no-wait 35 | nil, // arguments 36 | ) 37 | x.OnError(err, "Failed to declare a queue") 38 | 39 | err = ch.Publish( 40 | "", // exchange 41 | q.Name, // routing key 42 | false, // mandatory 43 | false, // immediate 44 | amqp.Publishing{ 45 | ContentType: contentType, 46 | Body: body, 47 | }) 48 | x.OnError(err, "Failed to publish a message") 49 | } 50 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | networks: 4 | rabbitmq-example: 5 | driver: bridge 6 | 7 | services: 8 | rabbitmq: 9 | image: 'rabbitmq:3-management' 10 | networks: 11 | - rabbitmq-example 12 | volumes: 13 | - ./rabbit-mq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro 14 | ports: 15 | - "8080:15672" 16 | # - "5000:5673" # Expose this port while running the producer and consumer services locally 17 | healthcheck: 18 | test: [ "CMD", "rabbitmqctl", "status"] 19 | interval: 5s 20 | timeout: 15s 21 | retries: 5 22 | producer: 23 | build: ./producer 24 | ports: 25 | - "5050:5050" # Port to access our REST API 26 | networks: 27 | - rabbitmq-example 28 | depends_on: 29 | - rabbitmq 30 | environment: # Sample env variables for producer 31 | GIN_MODE: "release" 32 | GIN_HTTPS: "false" 33 | GIN_ADDR: "0.0.0.0" 34 | GIN_PORT: "5050" 35 | LOG_LEVEL: "debug" 36 | RMQ_URL: "amqp://guest:guest@rabbitmq:5673/" 37 | consumer: 38 | build: ./consumer 39 | networks: 40 | - rabbitmq-example 41 | depends_on: 42 | - rabbitmq 43 | restart: on-failure 44 | environment: # Sample env variables for consumer 45 | LOG_LEVEL: "debug" 46 | RMQ_URL: "amqp://guest:guest@rabbitmq:5673/" 47 | -------------------------------------------------------------------------------- /consumer/utils/rmq_consumer.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/rs/zerolog/log" 5 | "github.com/streadway/amqp" 6 | ) 7 | 8 | type RMQConsumer struct { 9 | Queue string 10 | ConnectionString string 11 | MsgHandler func(queue string, msg amqp.Delivery, err error) 12 | } 13 | 14 | func (x RMQConsumer) OnError(err error, msg string) { 15 | if err != nil { 16 | x.MsgHandler(x.Queue, amqp.Delivery{}, err) 17 | } 18 | } 19 | 20 | func (x RMQConsumer) Consume() { 21 | conn, err := amqp.Dial(x.ConnectionString) 22 | x.OnError(err, "Failed to connect to RabbitMQ") 23 | defer conn.Close() 24 | 25 | ch, err := conn.Channel() 26 | x.OnError(err, "Failed to open a channel") 27 | defer ch.Close() 28 | 29 | q, err := ch.QueueDeclare( 30 | x.Queue, // name 31 | false, // durable 32 | false, // delete when unused 33 | false, // exclusive 34 | false, // no-wait 35 | nil, // arguments 36 | ) 37 | x.OnError(err, "Failed to declare a queue") 38 | 39 | msgs, err := ch.Consume( 40 | q.Name, // queue 41 | "", // consumer 42 | true, // auto-ack 43 | false, // exclusive 44 | false, // no-local 45 | false, // no-wait 46 | nil, // args 47 | ) 48 | x.OnError(err, "Failed to register a consumer") 49 | 50 | forever := make(chan bool) 51 | 52 | go func() { 53 | for d := range msgs { 54 | x.MsgHandler(x.Queue, d, nil) 55 | } 56 | }() 57 | log.Info().Msgf("Started listening for messages on '%s' queue", x.Queue) 58 | <-forever 59 | } 60 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Example for using RabbitMQ with Golang 2 | This repository contains the example code for publishing and reading a message to and from an RabbitMQ message queue. I have also written a [blog](https://medium.com/@hinsulak/using-rabbitmq-with-golang-and-docker-e674831c959c) for the same, feel free to check it out. 3 | This repository also contains Dockerfile and docker-compose.yaml files for deploying these services using Docker. 4 | 5 | ## Run locally 6 | ### Producer 7 | Follow these steps to run the producer service locally, 8 | - At the repository root, execute the following command to open the producer directory. 9 | `cd .\producer\` 10 | - Get dependencies. 11 | `go get .` 12 | - Set the environment variables - use the sample .env file provided in the repository. 13 | - Execute the `go run main.go` command to start the service. 14 | ### Consumer 15 | Follow these steps to run the consumer service locally, 16 | - At the repository root, execute the following command to open the consumer directory. 17 | `cd .\consumer\` 18 | - Get dependencies. 19 | `go get .` 20 | - Set the environment variables - use the sample .env file provided in the repository. 21 | - Execute the `go run main.go` command to start the service. 22 | ### RabbitMQ 23 | - There is a docker-compose.yaml file in the repository. 24 | - Uncomment the `- "5000:5673"` to expose the RabbitMQ instance outside docker. 25 | - [Optionally] Comment out the `producer` and `consumer` service specs so that they are not deployed in the docker. 26 | 27 | ## Running in Docker 28 | - Running in Docker is very simple, the repo includes a `docker-compose.yaml` file. 29 | - At the repository root, execute `docker-compose up` command to deploy the RabbitMQ instance, producer, and consumer services. 30 | - The producer REST API will be available at `http://localhost:5050/v1/publish/example` if the default configuration is used. 31 | -------------------------------------------------------------------------------- /producer/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lakhinsu/rabbitmq-go-example/producer 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.7.7 7 | github.com/streadway/amqp v1.0.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 14 | ) 15 | 16 | require ( 17 | github.com/fsnotify/fsnotify v1.5.1 // indirect 18 | github.com/gin-contrib/sse v0.1.0 // indirect 19 | github.com/go-playground/locales v0.13.0 // indirect 20 | github.com/go-playground/universal-translator v0.17.0 // indirect 21 | github.com/go-playground/validator/v10 v10.4.1 // indirect 22 | github.com/golang/protobuf v1.5.2 // indirect 23 | github.com/google/uuid v1.3.0 24 | github.com/hashicorp/hcl v1.0.0 // indirect 25 | github.com/json-iterator/go v1.1.12 // indirect 26 | github.com/leodido/go-urn v1.2.0 // indirect 27 | github.com/magiconair/properties v1.8.5 // indirect 28 | github.com/mattn/go-isatty v0.0.14 // indirect 29 | github.com/mitchellh/mapstructure v1.4.3 // indirect 30 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 31 | github.com/modern-go/reflect2 v1.0.2 // indirect 32 | github.com/pelletier/go-toml v1.9.4 // indirect 33 | github.com/rs/zerolog v1.26.1 34 | github.com/spf13/afero v1.6.0 // indirect 35 | github.com/spf13/cast v1.4.1 // indirect 36 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 37 | github.com/spf13/pflag v1.0.5 // indirect 38 | github.com/spf13/viper v1.10.1 39 | github.com/stretchr/testify v1.7.0 40 | github.com/subosito/gotenv v1.2.0 // indirect 41 | github.com/ugorji/go/codec v1.1.7 // indirect 42 | golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e // indirect 43 | golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect 44 | golang.org/x/text v0.3.7 // indirect 45 | google.golang.org/protobuf v1.27.1 // indirect 46 | gopkg.in/ini.v1 v1.66.2 // indirect 47 | gopkg.in/yaml.v2 v2.4.0 // indirect 48 | ) 49 | -------------------------------------------------------------------------------- /consumer/go.sum: -------------------------------------------------------------------------------- 1 | github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= 5 | github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= 6 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 7 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 8 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 9 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 10 | github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= 11 | github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 12 | github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= 13 | github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 14 | github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= 15 | github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 16 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 17 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 18 | github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 19 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 20 | github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 21 | github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= 22 | github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= 23 | github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= 24 | github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= 25 | github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= 26 | github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 27 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 28 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 29 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 30 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 31 | github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= 32 | github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= 33 | github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= 34 | github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 35 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 36 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 37 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 38 | github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= 39 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 40 | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 41 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 42 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 43 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 44 | golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 45 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 46 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 47 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 48 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 49 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 50 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 51 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 52 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 53 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 54 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 55 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 56 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 57 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 58 | golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= 59 | golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 60 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 61 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 62 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 63 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 64 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 65 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 66 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 67 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 68 | golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 69 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 70 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 71 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 72 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 73 | gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= 74 | gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 75 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 76 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 77 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 78 | -------------------------------------------------------------------------------- /producer/go.sum: -------------------------------------------------------------------------------- 1 | github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= 6 | github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= 7 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 8 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 9 | github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= 10 | github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= 11 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 12 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 13 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 14 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 15 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 16 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 17 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 18 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 19 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 20 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 21 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 22 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 23 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 24 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 25 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 26 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 27 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 28 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 29 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 30 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 31 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 32 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 33 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 34 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 35 | github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= 36 | github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= 37 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 38 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 39 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 40 | github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= 41 | github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 42 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 43 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 44 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 45 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 46 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 47 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 48 | github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= 49 | github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= 50 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 51 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 52 | github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= 53 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 54 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 55 | github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 56 | github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= 57 | github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= 58 | github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= 59 | github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= 60 | github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= 61 | github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 62 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 63 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 64 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 65 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 66 | github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= 67 | github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= 68 | github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo= 69 | github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 70 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 71 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 72 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 73 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 74 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 75 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 76 | github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= 77 | github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 78 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 79 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 80 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 81 | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 82 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 83 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 84 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 85 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 86 | golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e h1:1SzTfNOXwIS2oWiMF+6qu0OUDKb0dauo6MoDUQyu+yU= 87 | golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 88 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 89 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 90 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 91 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 92 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 93 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 94 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 95 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 96 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 97 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 98 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 99 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 100 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 101 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 102 | golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= 103 | golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 104 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 105 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 106 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 107 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 108 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 109 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 110 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 111 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 112 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 113 | golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 114 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 115 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 116 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 117 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 118 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 119 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 120 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 121 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 122 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 123 | gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= 124 | gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 125 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 126 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 127 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 128 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 129 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 130 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 131 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 132 | --------------------------------------------------------------------------------