25. NSQ 簡介及教程

NSQ 簡介及教程

What is nsq

NSQ is a realtime distributed messaging platform.

IntroduceLinks

Why use nsq

Features-guarantess

How to use nsq

Example

Install

docker-compose.yaml

version: '3'
services:
  nsqlookupd:
    image: nsqio/nsq
    command: /nsqlookupd
    ports:
      - "4160:4160"
      - "4161:4161"
  nsqd:
    image: nsqio/nsq
    command: /nsqd --lookupd-tcp-address=nsqlookupd:4160 --broadcast-address=10.1.4.130
    depends_on:
      - nsqlookupd
    ports:
      - "4150:4150"
      - "4151:4151"
  nsqadmin:
    image: nsqio/nsq
    command: /nsqadmin --lookupd-http-address=nsqlookupd:4161
    depends_on:
      - nsqlookupd  
    ports:
      - "4171:4171"

TestCase

Consumer

consumer_test.go

package comsumer

import (
	"github.com/nsqio/go-nsq"
	"log"
	"testing"
	"time"
)

var (
	nsqLookupdAddr = "10.1.4.130:4161"
)

func TestConsumer1(t *testing.T) {
	config := nsq.NewConfig()
	topic := "t1"
	channel := "t1-c1"
	c, err := nsq.NewConsumer(topic, channel, config)

	if err != nil {
		log.Fatalf("init consumer fail, err: %s", err.Error())
	}

	c.AddHandler(&msgHandler1{})

	// Use nsqlookupd to discover nsqd instances.
	// See also ConnectToNSQD, ConnectToNSQDs, ConnectToNSQLookupds.
	err = c.ConnectToNSQLookupd(nsqLookupdAddr)
	if err != nil {
		log.Fatalf("ConnectToNSQLookupd fail, err: %s", err.Error())
	}

	time.Sleep(time.Duration(100) * time.Minute)
}

func TestConsumer2(t *testing.T) {
	config := nsq.NewConfig()
	config.MaxInFlight = 100

	topic := "t1"
	channel := "t1-c2"
	c, err := nsq.NewConsumer(topic, channel, config)

	if err != nil {
		log.Fatalf("init consumer fail, err: %s", err.Error())
	}

	c.AddHandler(&msgHandler2{})

	// Use nsqlookupd to discover nsqd instances.
	// See also ConnectToNSQD, ConnectToNSQDs, ConnectToNSQLookupds.
	err = c.ConnectToNSQLookupd(nsqLookupdAddr)
	if err != nil {
		log.Fatalf("ConnectToNSQLookupd fail, err: %s", err.Error())
	}

	time.Sleep(time.Duration(100) * time.Minute)
}

types.go

package comsumer

import (
	"time"
	"fmt"
	"github.com/nsqio/go-nsq"
)

// ===
// msg handler 1

type msgHandler1 struct {
}

func (_ *msgHandler1) HandleMessage(m *nsq.Message) error {
	handlerName := "msgHandler1"
	var err error
	if len(m.Body) == 0 {
		// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
		return nil
	}

	// handle msg
	msg := m.Body
	fmt.Printf("%s received msg: %s\n", handlerName, msg)

	if err != nil {
		// Returning a non-nil error will automatically send a REQ command to NSQ to re-queue the message.
		return err
	}

	return nil
}

// ===
// msg handler 2

type msgHandler2 struct {
}

func (_ *msgHandler2) HandleMessage(m *nsq.Message) error {
	handlerName := "msgHandler2"
	if len(m.Body) == 0 {
		// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
		return nil
	}

	// handle msg
	msg := string(m.Body)

	if time.Now().Unix()%2 == 0 {
		fmt.Printf("%s received msg: %s, attempts: %d\n", handlerName, msg, m.Attempts)
		return nil
	} else {
		if m.Attempts >= 2 {
			fmt.Printf("%s received msg: %s, attempts: %d\n", handlerName, msg, m.Attempts)
			return nil
		} else {
			return fmt.Errorf("%s need re-queue msg: %s, attempts: %d\n", handlerName, msg, m.Attempts)
		}

	}
}

Producer

producer_test.go

package producer

import (
	"github.com/nsqio/go-nsq"
	"testing"
	"log"
	"time"
	"fmt"
	"encoding/json"
)

var (
	nsqdAddr = "10.1.4.130:4150"
	p        *nsq.Producer
)

func init() {
	newProducer()
}

func newProducer() (*nsq.Producer, error) {
	config := nsq.NewConfig()
	return nsq.NewProducer(nsqdAddr, config)
}

func TestMain(m *testing.M) {
	if p == nil {
		var err error
		p, err = newProducer()
		if err != nil {
			panic(err)
		}
	}
	m.Run()
}

func TestSimplePublish(t *testing.T) {
	if err := p.Ping(); err != nil {
		log.Fatalf("ping nsqd fail, err: %s", err.Error())
	}
	topic := "t1"
	msg := []byte("this is simple msg")
	p.Publish(topic, msg)

	time.Sleep(100 * time.Minute)

}

func TestMultiPublish(t *testing.T) {
	topic := "t1"
	var msgs [][]byte
	for i := 1; i <= 50; i ++ {
		msg := fmt.Sprintf("msg-%d", i)
		msgs = append(msgs, []byte(msg))
	}

	p.MultiPublish(topic, msgs)
}

func TestDeferredPublish(t *testing.T) {
	topic := "t1"
	delay := time.Duration(30) * time.Second
	msg := []byte("deferred msg")
	if err := p.DeferredPublish(topic, delay, msg); err != nil {
		log.Fatalf("deferred publish fail, err: %s\n", err.Error())
	}

	p.Stop()
}

func TestPublishAsync(t *testing.T) {
	topic := "t1"
	msg := []byte("async msg")

	doChan := make(chan *nsq.ProducerTransaction, 1)
	if err := p.PublishAsync(topic, msg, doChan, "arg1", 2); err != nil {
		log.Fatalf("publish async fail, err: %s\n", err.Error())
	}

	for {
		select {
		case res := <-doChan:
			argsBytes, _ := json.Marshal(res.Args)
			fmt.Printf("args: %s\n", string(argsBytes))
			if res.Error != nil {
				fmt.Printf("err: %s\n", res.Error.Error())
			}
			return
		default:

		}
	}

	p.Stop()
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章