/
golery.go
144 lines (114 loc) · 3.04 KB
/
golery.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package golery
import (
"github.com/streadway/amqp"
"log"
"os"
"strconv"
)
type Route struct {
QueueName string
Fn func([]byte)
Workers int
}
type Config struct {
RABBITMQ_URL string
routeMap map[string]Route
}
func GetConfig(routes []Route) Config {
var RABBITMQ_URL = "amqp://guest:guest@localhost:5672/"
var routeMap = make(map[string]Route)
if os.Getenv("RABBITMQ_URL") != "" {
RABBITMQ_URL = os.Getenv("RABBITMQ_URL")
}
for i := 0; i < len(routes); i++ {
routeMap[routes[i].QueueName] = routes[i]
}
return Config{RABBITMQ_URL: RABBITMQ_URL, routeMap: routeMap}
}
func createQueue(channel *amqp.Channel, queueName string) {
err := channel.ExchangeDeclare(
queueName, // name of the exchange
"direct", // type
true, // durable
false, // delete when complete
false, // internal
false, // noWait
nil, // arguments
)
if err != nil {
log.Fatal("Couldn't declare exchange: %s", err)
}
queue, err := channel.QueueDeclare(
queueName, // name of the queue
true, // durable
false, // delete when usused
false, // exclusive
false, // noWait
nil, // arguments
)
if err != nil {
log.Fatal("Couldn't declare queue: %s", err)
}
err = channel.QueueBind(
queue.Name, // name of the queue
queueName, // bindingKey
queueName, // sourceExchange
false, // noWait
nil, // arguments
)
if err != nil {
log.Fatal("Couldn't bind queue: %s", err)
}
}
func messageConsumerWorker(messageChannel chan []byte, fn func([]byte), workerName string) {
defer func() {
if r := recover(); r != nil {
log.Println("Recover from", r)
}
}()
for message := range messageChannel {
log.Println("Message received on worker ", workerName)
fn(message)
}
}
func StartQueueConsumer(queueName string, config Config, TerminatedConsumerChannel chan<- bool) {
var connection, err = amqp.Dial(config.RABBITMQ_URL)
if err != nil {
log.Fatal("connection.open: %s", err)
}
defer connection.Close()
channel, err := connection.Channel()
if err != nil {
log.Fatal("channel.open: %s", err)
}
createQueue(channel, queueName)
messages, err := channel.Consume(queueName, queueName, true, false, false, false, nil)
if err != nil {
log.Fatal("basic.consume: %v", err)
}
var messageChannel = make(chan []byte)
var workers = 1
if config.routeMap[queueName].Workers > 0 {
workers = config.routeMap[queueName].Workers
}
// Start the workers
for i := 0; i < workers; i++ {
workerName := queueName + "." + strconv.Itoa(i)
go messageConsumerWorker(messageChannel, config.routeMap[queueName].Fn, workerName)
}
// Push messages into channel
for message := range messages {
messageChannel <- message.Body
}
TerminatedConsumerChannel <- true
}
func Start(routes []Route) {
var config = GetConfig(routes)
var TerminatedConsumerChannel = make(chan bool, len(routes))
for queueName, _ := range config.routeMap {
go StartQueueConsumer(queueName, config, TerminatedConsumerChannel)
}
for i := 0; i < len(routes); i++ {
<-TerminatedConsumerChannel
}
}