我正在创建一个工作程序以使用RabitMQ队列中的消息。为此,我创建了一个名为queue.go
的文件
package ExternalServices
import (
"../domain"
"encoding/json"
"github.com/streadway/amqp"
"os"
)
const (
catalogQueue = "catalog-queue"
)
func EnqueueMessageCatalog(catalog *domain.Catalog) error {
marshal, err := json.Marshal(*catalog)
if err != nil {
return err
}
jsonVal := string(marshal)
err = enqueue(catalogQueue, jsonVal)
return err
}
func DequeueMessageCatalog() ([]domain.Catalog, error) {
msgs, err := dequeue(catalogQueue)
if err != nil {
return nil, err
}
allCatalogs := make([]domain.Catalog, len(msgs))
for _, currMsg := range msgs {
var currCatalog domain.Catalog
err = json.Unmarshal([]byte(currMsg), &currCatalog)
if err != nil {
return nil, err
}
}
return allCatalogs, nil
}
func openConnection() (*amqp.Connection, *amqp.Channel, error) {
conn, err := amqp.Dial(os.Getenv("RabbitMQConStr"))
if err != nil {
return nil, nil, err
}
ch, err := conn.Channel()
if err != nil {
conn.Close()
return nil, nil, err
}
return conn, ch, nil
}
func ensureQueueExists(queueName string, ch *amqp.Channel) (amqp.Queue, error) {
q, err := ch.QueueDeclare(
queueName, // name
false, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
return q, err
}
func enqueue(queueName string, message string) error {
con, ch, err := openConnection()
if err != nil {
return err
}
defer con.Close()
defer ch.Close()
q, err := ensureQueueExists(queueName, ch)
if err != nil {
return err
}
err = ch.Publish(
"", // exchange
q.Name, // routing key
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "application/json",
Body: []byte(message),
})
return err
}
func dequeue(queueName string) ([]string, error) {
con, ch, err := openConnection()
if err != nil {
return nil, err
}
defer con.Close()
defer ch.Close()
q, err := ensureQueueExists(queueName, ch)
if err != nil {
return nil, err
}
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
if err != nil {
return nil, err
}
jsons := make([]string, len(msgs))
i := 0
for currMsg:= range msgs {
jsons[i] = string(currMsg.Body)
i += 1
}
return jsons, nil
}
但是,我对dequeue
函数有些困惑。我希望每次有消息到达队列时都通知我的工作人员,所以我想这样做的正确方法是为我的工作人员创建一个字符串chan,因为我不想公开{{ 1}}。
到目前为止,这是我的工人。
Consume
package worker
import (
"../external-services"
"log"
)
func StartWorker() {
go func() {
messages, err := ExternalServices.DequeueMessageCatalog();
if err != nil {
// todo log
}
for d := range messages {
log.Printf("Received a message: %s", d)
}
}()
}
函数,使其返回字符串chan? dequeue
和defer con.Close()
?这是我在GoLang中的第一个项目,因此,您认为可以提高代码质量的任何事情都会受到赞赏:-D
答案 0 :(得分:2)
也许是这样的:
msgs, err := ch.Consume(...)
/* handle error */
stringCh := make(chan string)
done := make(chan struct{})
go func() {
defer con.Close()
defer ch.Close()
defer close(stringCh)
for {
select {
case currMsg := <-msgs:
stringCh <- string(currMsg.Body)
case <-done:
return
}
}
}()
return stringCh, done
这只是一个粗略的例子。基本思想是生成另一个goroutine来监听Consume返回的消息chan。其他详细信息,例如如何正常关机,出队界面等等,取决于您的需求。
答案 1 :(得分:0)
在阅读@YSTai回复后,我意识到我错过了go例程的创建。这就是我的代码结束的方式。
worker.go
package main
import (
"../domain"
"../externalservices"
"log"
"strings"
"sync"
)
/*
StartWorker initializes a program that will wait for messages enqueued and process them
*/
func StartWorker() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
catalogReceived := make(chan domain.Catalog)
defer close(catalogReceived)
for true {
go func() {
externalservices.DequeueMessageCatalog(catalogReceived)
catalog := <-catalogReceived
website := domain.Website{
Name: strings.ToUpper(catalog.Name),
Zip: catalog.Zip}
externalservices.InsertWebSite(&website)
}()
}
}()
log.Printf(" [*] Waiting for messages")
wg.Wait()
}
func main() {
StartWorker()
}
queue.go
package externalservices
import (
"../domain"
"encoding/json"
"github.com/streadway/amqp"
"os"
)
const (
catalogQueue = "catalog-queue"
)
func EnqueueMessageCatalog(catalog *domain.Catalog) error {
marshal, err := json.Marshal(*catalog)
if err != nil {
return err
}
jsonVal := string(marshal)
err = enqueue(catalogQueue, jsonVal)
return err
}
// DequeueMessageCatalog is nice
func DequeueMessageCatalog(messageChannel chan domain.Catalog) {
message := make(chan []byte)
defer close(message)
for true {
go func() {
dequeue(catalogQueue, message)
}()
currCatalog := domain.Catalog{}
json.Unmarshal([]byte(<-message), &currCatalog)
messageChannel <- currCatalog
}
}
func openConnection() (*amqp.Connection, *amqp.Channel, error) {
connString := os.Getenv("RabbitMQConStr")
conn, err := amqp.Dial(connString)
if err != nil {
return nil, nil, err
}
ch, err := conn.Channel()
if err != nil {
conn.Close()
return nil, nil, err
}
return conn, ch, nil
}
func ensureQueueExists(queueName string, ch *amqp.Channel) (amqp.Queue, error) {
q, err := ch.QueueDeclare(
queueName, // name
false, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
return q, err
}
func enqueue(queueName string, message string) error {
con, ch, err := openConnection()
if err != nil {
return err
}
defer con.Close()
defer ch.Close()
q, err := ensureQueueExists(queueName, ch)
if err != nil {
return err
}
err = ch.Publish(
"", // exchange
q.Name, // routing key
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "application/json",
Body: []byte(message),
})
return err
}
func dequeue(queueName string, message chan []byte) error {
con, ch, err := openConnection()
if err != nil {
return err
}
defer con.Close()
defer ch.Close()
q, err := ensureQueueExists(queueName, ch)
if err != nil {
return err
}
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto-ack
false, // exclusive
false, // no-local
true, // no-wait
nil, // args
)
if err != nil {
return err
}
for currMsg := range msgs {
message <- currMsg.Body
}
return nil
}