RocketMQ部署及使用-Go (四)

221 阅读6分钟

在篇章(三)中,由于我的废话实在是太多,鉴于此,这章索性我就直接把example code粘贴出来。talk is cheap,show me the code。

async

consumer

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "github.com/pkg/errors"
    "log"
    "os"
    "time"

    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
)

const (
    Topic = "containerExpireDelayTopic"
    //Endpoint  = "10.101.26.151:8080"
    Endpoint      = "127.0.0.1:8080"
    AccessKey     = ""
    SecretKey     = ""
    ConsumerGroup = "ContainerExpireInformGroup"
    Tag           = "containerExpireInform"
)

var (
    // maximum waiting time for receive func
    awaitDuration = time.Second * 5
    // maximum number of messages received at one time
    maxMessageNum int32 = 16
    // invisibleDuration should > 20s,Message retry interval = InvisibleDuration value − Actual duration of message processing
    invisibleDuration = time.Second * 20
)

type ContainerExpireRequest struct {
    ContainerId string    `json:"containerId" form:"containerId"` // 容器ID
    EndTime     time.Time `json:"endTime" form:"endTime"`         // 到期时间
}

func main() {

    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()

    // new simpleConsumer instance
    simpleConsumer, err := golang.NewSimpleConsumer(&golang.Config{
       Endpoint:      Endpoint,
       ConsumerGroup: ConsumerGroup,
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },

       golang.WithAwaitDuration(awaitDuration),
       golang.WithSubscriptionExpressions(map[string]*golang.FilterExpression{
          Topic: golang.NewFilterExpression(Tag),
       }),
    )
    if err != nil {
       log.Fatal(err)
    }

    // start simpleConsumer
    err = simpleConsumer.Start()
    if err != nil {
       log.Fatal(err)
    }

    // graceful stop simpleConsumer
    defer simpleConsumer.GracefulStop()

    go func() {
       for {
          fmt.Println("start receive message...")
          mvs, err := simpleConsumer.Receive(context.TODO(), maxMessageNum, invisibleDuration)
          var rpcStatus *golang.ErrRpcStatus
          if ok := errors.As(err, &rpcStatus); ok {
             if rpcStatus.GetCode() != 40401 && rpcStatus.GetMessage() != "no new message" {
                fmt.Printf("Failed to receive message for group %s: %v\n", simpleConsumer.GetGroupName(), err)
             }
          }
          for _, mv := range mvs {
             // 模拟处理失败
             if err = dealMes(); err != nil {
                fmt.Println("消费失败...")
                if mv.GetDeliveryAttempt() > 3 {
                   fmt.Println("delivery time :", mv.GetDeliveryAttempt())
                   //ack message,consumer retry times: default 16
                   simpleConsumer.Ack(context.TODO(), mv)

                   message := &ContainerExpireRequest{}
                   err = json.Unmarshal(mv.GetBody(), message)
                   if err != nil {
                      fmt.Printf("containerExpireInform unmarshal message err:%v,tag:%v\n", err, mv.GetTag())
                      continue
                   }
                   if mv.GetDeliveryAttempt() > 3 {
                      fmt.Printf("containerExpireInform consume message max attempts is greater than 3,messageId:%v\n", mv.GetMessageId())
                      // ack message
                      simpleConsumer.Ack(context.TODO(), mv)

                      // TODO: exec rollback logic

                      continue
                   }
                   simpleConsumer.Ack(context.TODO(), mv)
                }
             }
          }
       }
    }()
    select {}
}
func dealMes() error {
    return errors.New("deal message error")
}

producer

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
    "log"
    "os"
    "time"
)

const (
    Topic = "containerExpireDelayTopic"
    //Endpoint  = "10.101.26.151:8080"
    Endpoint  = "10.101.26.151:8080"
    AccessKey = ""
    SecretKey = ""
    Tag       = "containerExpireInform"
)

type ContainerExpireRequest struct {
    ContainerId string    `json:"containerId" form:"containerId"` // 容器ID
    EndTime     time.Time `json:"endTime" form:"endTime"`         // 到期时间
}

func main() {

    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()

    // new producer instance
    producer, err := golang.NewProducer(&golang.Config{
       Endpoint: Endpoint,
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },
       golang.WithTopics(Topic),
       golang.WithMaxAttempts(3), // set max attempts,default is 3
    )
    if err != nil {
       log.Fatal(err)
    }

    // start producer
    err = producer.Start()
    if err != nil {
       log.Fatal(err)
    }

    shanghaiLoc, err := time.LoadLocation("Asia/Shanghai")
    if err != nil {
       log.Fatal(err)
    }

    // gracefule stop producer
    defer producer.GracefulStop()
    
    message := ContainerExpireRequest{
       ContainerId: "test-containerId-测试",
       EndTime:     time.Now().In(shanghaiLoc).Add(time.Second * 5),
    }
    jsonData, err := json.Marshal(message)
    if err != nil {
       return
    }
    msg := &golang.Message{
       Topic: Topic,
       Body:  []byte(jsonData),
    }

    // set keys and tag
    msg.SetKeys("test-key")
    msg.SetTag(Tag)

    // set delay timestamp
    msg.SetDelayTimestamp(time.Now().In(shanghaiLoc).Add(time.Second * 5))

    // send message in async
    resp, err := producer.Send(context.TODO(), msg)
    if err != nil {
       log.Fatal(err)
    }
    for i := 0; i < len(resp); i++ {
       fmt.Printf("%#v\n", resp[i])
    }

    select {}
}

delay

consumer

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
)

const (
    Topic     = "DelayTopic"
    Endpoint  = "127.0.0.1:8080"
    AccessKey = "xxxxxx"
    SecretKey = "xxxxxx"
)

var (
    // maximum waiting time for receive func
    awaitDuration = time.Second * 5
    // maximum number of messages received at one time
    maxMessageNum int32 = 16
    // invisibleDuration should > 20s,Message retry interval = InvisibleDuration value − Actual duration of message processing
    invisibleDuration = time.Second * 20
)

func main() {
    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()
    // new simpleConsumer instance
    simpleConsumer, err := golang.NewSimpleConsumer(&golang.Config{
       Endpoint:      Endpoint,
       ConsumerGroup: "test-async-group",
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },
       golang.WithAwaitDuration(awaitDuration),
       golang.WithSubscriptionExpressions(map[string]*golang.FilterExpression{
          Topic: golang.SUB_ALL,
       }),
    )
    if err != nil {
       log.Fatal(err)
    }
    // start simpleConsumer
    err = simpleConsumer.Start()
    if err != nil {
       log.Fatal(err)
    }
    // gracefule stop simpleConsumer
    defer simpleConsumer.GracefulStop()

    shanghaiLoc, err := time.LoadLocation("Asia/Shanghai")
    if err != nil {
       log.Fatal(err)
    }

    go func() {
       for {
          fmt.Println("start recevie message")
          mvs, err := simpleConsumer.Receive(context.TODO(), maxMessageNum, invisibleDuration)
          if err != nil {
             fmt.Println(err)
          }
          // ack message
          for _, mv := range mvs {
             simpleConsumer.Ack(context.TODO(), mv) // consumer retry times: default 16
             fmt.Printf("message:%v  send time:%v   receive time:%v\n", string(mv.GetBody()), mv.GetBornTimestamp().In(shanghaiLoc).Format("2006-01-02 15:04:05"), time.Now().In(shanghaiLoc).Format("2006-01-02 15:04:05"))
          }
          fmt.Println("wait a moment")
       }
    }()
    // run for a while
    select {}
}

producer

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"
    "time"

    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
)

const (
    Topic     = "DelayTopic"
    Endpoint  = "127.0.0.1:8080"
    AccessKey = "xxxxxx"
    SecretKey = "xxxxxx"
)

func main() {
    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()
    // new producer instance
    producer, err := golang.NewProducer(&golang.Config{
       Endpoint: Endpoint,
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },
       golang.WithTopics(Topic),
    )
    if err != nil {
       log.Fatal(err)
    }
    // start producer
    err = producer.Start()
    if err != nil {
       log.Fatal(err)
    }

    shanghaiLoc, err := time.LoadLocation("Asia/Shanghai")
    if err != nil {
       log.Fatal(err)
    }

    // gracefule stop producer
    defer producer.GracefulStop()
    for i := 0; i < 3; i++ {
       // new a message
       msg := &golang.Message{
          Topic: Topic,
          Body:  []byte("this is a message : " + strconv.Itoa(i)),
       }
       // set keys and tag
       msg.SetKeys("delay")
       msg.SetTag("ab")
       // set delay timestamp
       msg.SetDelayTimestamp(time.Now().In(shanghaiLoc).Add(time.Second * 10))
       // send message in sync
       resp, err := producer.Send(context.TODO(), msg)
       if err != nil {
          log.Fatal(err)
       }
       for i := 0; i < len(resp); i++ {
          fmt.Printf("%#v\n", resp[i])
       }
    }
}

// sh mqadmin updateTopic -c DefaultCluster -t DelayTopic -n rmqnamesrv:9876 -a +message.type=DELAY

fifo

consumer

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
)

const (
    Topic     = "FIFOTopic"
    Endpoint  = "127.0.0.1:8080"
    AccessKey = ""
    SecretKey = ""
)

var (
    // maximum waiting time for receive func
    awaitDuration = time.Second * 5
    // maximum number of messages received at one time
    maxMessageNum int32 = 16
    // invisibleDuration should > 20s,Message retry interval = InvisibleDuration value − Actual duration of message processing
    invisibleDuration = time.Second * 20
)

func main() {
    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()
    // new simpleConsumer instance
    simpleConsumer, err := golang.NewSimpleConsumer(&golang.Config{
       Endpoint:      Endpoint,
       ConsumerGroup: "test-fifo-group",
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },
       golang.WithAwaitDuration(awaitDuration),
       golang.WithSubscriptionExpressions(map[string]*golang.FilterExpression{
          Topic: golang.SUB_ALL,
       }),
    )
    if err != nil {
       log.Fatal(err)
    }
    // start simpleConsumer
    err = simpleConsumer.Start()
    if err != nil {
       log.Fatal(err)
    }
    // gracefule stop simpleConsumer
    defer simpleConsumer.GracefulStop()

    shanghaiLoc, err := time.LoadLocation("Asia/Shanghai")
    if err != nil {
       log.Fatal(err)
    }

    go func() {
       for {
          fmt.Println("start recevie message")
          mvs, err := simpleConsumer.Receive(context.TODO(), maxMessageNum, invisibleDuration)
          if err != nil {
             fmt.Println(err)
          }
          // ack message
          for _, mv := range mvs {
             simpleConsumer.Ack(context.TODO(), mv) // consumer retry times: default 16
             fmt.Printf("message:%v  send time:%v   receive time:%v\n", string(mv.GetBody()), mv.GetBornTimestamp().In(shanghaiLoc).Format("2006-01-02 15:04:05"), time.Now().In(shanghaiLoc).Format("2006-01-02 15:04:05"))
          }
          fmt.Println("wait a moment")
       }
    }()
    // run for a while
    select {}
}

// sh mqadmin updateSubGroup -c DefaultCluster -g orderconsumergroup -n rmqnamesrv:9876 -o true

producer

package main

import (
    "context"
    "fmt"
    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
    "log"
    "os"
    "strconv"
)

const (
    Topic     = "FIFOTopic"
    Endpoint  = "127.0.0.1:8080"
    AccessKey = ""
    SecretKey = ""
)

func main() {
    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()
    // new producer instance
    producer, err := golang.NewProducer(&golang.Config{
       Endpoint: Endpoint,
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },
       golang.WithTopics(Topic),
    )
    if err != nil {
       log.Fatal(err)
    }
    // start producer
    err = producer.Start()
    if err != nil {
       log.Fatal(err)
    }
    // gracefule stop producer
    defer producer.GracefulStop()
    for i := 0; i < 100; i++ {
       // new a message
       msg := &golang.Message{
          Topic: Topic,
          Body:  []byte("message: " + strconv.Itoa(i)),
       }
       // set keys and tag
       msg.SetKeys("fifo")
       msg.SetTag("ab")
       msg.SetMessageGroup("fifo") // set message group
       // send message in sync
       resp, err := producer.Send(context.TODO(), msg)
       if err != nil {
          log.Fatal(err)
       }
       for i := 0; i < len(resp); i++ {
          fmt.Printf("%#v\n", resp[i])
       }
    }
}

// sh mqadmin updateTopic -c DefaultCluster -t FIFOTopic -n rmqnamesrv:9876 -a +message.type=FIFO

normal

consumer

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
)

const (
    Topic     = "test-normal-topic"
    Endpoint  = "127.0.0.1:8080"
    AccessKey = ""
    SecretKey = ""
)

var (
    // maximum waiting time for receive func
    awaitDuration = time.Second * 5
    // maximum number of messages received at one time
    maxMessageNum int32 = 16
    // invisibleDuration should > 20s,Message retry interval = InvisibleDuration value − Actual duration of message processing
    invisibleDuration = time.Second * 20
    // receive messages in a loop
)

func main() {
    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()
    // new simpleConsumer instance
    simpleConsumer, err := golang.NewSimpleConsumer(&golang.Config{
       Endpoint:      Endpoint,
       ConsumerGroup: "test-normal-group",
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },

       golang.WithAwaitDuration(awaitDuration),
       golang.WithSubscriptionExpressions(map[string]*golang.FilterExpression{
          Topic: golang.SUB_ALL,
       }),
    )
    if err != nil {
       log.Fatal(err)
    }
    // start simpleConsumer
    err = simpleConsumer.Start()
    if err != nil {
       log.Fatal(err)
    }
    // gracefule stop simpleConsumer
    defer simpleConsumer.GracefulStop()

    go func() {
       for {
          fmt.Println("start recevie message")
          mvs, err := simpleConsumer.Receive(context.TODO(), maxMessageNum, invisibleDuration)
          if err != nil {
             fmt.Println(err)
          }
          // ack message
          for _, mv := range mvs {
             //simpleConsumer.Ack(context.TODO(), mv)
             fmt.Printf("%#v\n", mv)
          }
          fmt.Println("wait a moment")
       }
    }()
    // run for a while
    select {}
}

producer

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"
    "time"

    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
)

const (
    Topic     = "test-normal-topic"
    Endpoint  = "127.0.0.1:8080"
    AccessKey = ""
    SecretKey = ""
)

func main() {
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()
    // new producer instance
    producer, err := golang.NewProducer(&golang.Config{
       Endpoint: Endpoint,
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },
       golang.WithTopics(Topic),
    )
    if err != nil {
       log.Fatal(err)
    }
    // start producer
    err = producer.Start()
    if err != nil {
       log.Fatal(err)
    }
    // gracefule stop producer
    defer producer.GracefulStop()

    for i := 0; i < 1; i++ {
       // new a message
       msg := &golang.Message{
          Topic: Topic,
          Body:  []byte("message : " + strconv.Itoa(i)),
       }
       // set keys and tag
       msg.SetKeys("normal-message")
       msg.SetTag("normal")
       // send message in sync
       resp, err := producer.Send(context.TODO(), msg)
       if err != nil {
          log.Fatal(err)
       }
       for i := 0; i < len(resp); i++ {
          fmt.Printf("%#v\n", resp[i])
       }
       // wait a moment
       time.Sleep(time.Second * 1)
    }
}

transaction

consumer

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
)

const (
    Topic     = "TRANSACTIONTopic"
    Endpoint  = "127.0.0.1:8080"
    AccessKey = "xxxxxx"
    SecretKey = "xxxxxx"
)

var (
    // maximum waiting time for receive func
    awaitDuration = time.Second * 5
    // maximum number of messages received at one time
    maxMessageNum int32 = 16
    // invisibleDuration should > 20s,Message retry interval = InvisibleDuration value − Actual duration of message processing
    invisibleDuration = time.Second * 20
)

func main() {
    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")
    golang.ResetLogger()
    // new simpleConsumer instance
    simpleConsumer, err := golang.NewSimpleConsumer(&golang.Config{
       Endpoint:      Endpoint,
       ConsumerGroup: "test-transaction-group",
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },
       golang.WithAwaitDuration(awaitDuration),
       golang.WithSubscriptionExpressions(map[string]*golang.FilterExpression{
          Topic: golang.SUB_ALL,
       }),
    )
    if err != nil {
       log.Fatal(err)
    }
    // start simpleConsumer
    err = simpleConsumer.Start()
    if err != nil {
       log.Fatal(err)
    }
    // gracefule stop simpleConsumer
    defer simpleConsumer.GracefulStop()

    shanghaiLoc, err := time.LoadLocation("Asia/Shanghai")
    if err != nil {
       log.Fatal(err)
    }

    go func() {
       for {
          fmt.Println("start recevie message")
          mvs, err := simpleConsumer.Receive(context.TODO(), maxMessageNum, invisibleDuration)
          if err != nil {
             fmt.Println(err)
          }
          // ack message
          for _, mv := range mvs {
             simpleConsumer.Ack(context.TODO(), mv) // consumer retry times: default 16
             fmt.Printf("message:%v  send time:%v   receive time:%v\n", string(mv.GetBody()), mv.GetBornTimestamp().In(shanghaiLoc).Format("2006-01-02 15:04:05"), time.Now().In(shanghaiLoc).Format("2006-01-02 15:04:05"))
          }
          fmt.Println("wait a moment")
       }
    }()
    // run for a while
    select {}
}

producer

package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strconv"
    "time"

    "github.com/apache/rocketmq-clients/golang"
    "github.com/apache/rocketmq-clients/golang/credentials"
)

const (
    Topic     = "TRANSACTIONTopic"
    Endpoint  = "127.0.0.1:8080"
    AccessKey = "xxxxxx"
    SecretKey = "xxxxxx"
)

func main() {
    // log to console
    os.Setenv("mq.consoleAppender.enabled", "true")
    os.Setenv(golang.CLIENT_LOG_LEVEL, "error")

    golang.ResetLogger()
    // new producer instance
    producer, err := golang.NewProducer(&golang.Config{
       Endpoint: Endpoint,
       Credentials: &credentials.SessionCredentials{
          AccessKey:    AccessKey,
          AccessSecret: SecretKey,
       },
    },
       golang.WithTransactionChecker(&golang.TransactionChecker{
          Check: func(msg *golang.MessageView) golang.TransactionResolution {
             log.Printf("check transaction message:%v, messageId:%v", string(msg.GetBody()), msg.GetMessageId())
             return golang.COMMIT
          },
       }),
       golang.WithTopics(Topic),
    )
    if err != nil {
       log.Fatal(err)
    }
    // start producer
    err = producer.Start()
    if err != nil {
       log.Fatal(err)
    }
    // gracefule stop producer
    defer producer.GracefulStop()
    for i := 0; i < 10; i++ {
       // new a message
       msg := &golang.Message{
          Topic: Topic,
          Body:  []byte("message : " + strconv.Itoa(i)),
       }
       // set keys and tag
       msg.SetKeys("transaction")
       msg.SetTag("ab")
       // send message in sync
       transaction := producer.BeginTransaction()
       resp, err := producer.SendWithTransaction(context.TODO(), msg, transaction)
       if err != nil {
          log.Fatal(err)
       }

       if err := executeLocalTransaction(i); err != nil {
          if rbErr := transaction.RollBack(); rbErr != nil {
             log.Printf("回滚事务失败: %v", rbErr)
          }
          log.Printf("本地事务执行失败: %v", err)
          continue
       }

       for i := 0; i < len(resp); i++ {
          fmt.Printf("%#v\n", resp[i])
       }

       // commit transaction message
       err = transaction.Commit()
       if err != nil {
          log.Fatal(err)
       }
    }
}
func executeLocalTransaction(index int) error {
    // 模拟数据库操作
    log.Printf("执行本地事务,更新订单状态,index: %d", index)

    // 模拟业务逻辑
    if index%3 == 0 {
       return fmt.Errorf("模拟本地事务执行失败,index: %d", index)
    }

    // 模拟执行时间
    time.Sleep(time.Millisecond * 10)
    return nil
}

// sh mqadmin updateTopic -c DefaultCluster -t TRANSACTIONTopic -n rmqnamesrv:9876 -a +message.type=TRANSACTION