1. 程式人生 > >使用Redis做任務佇列(Golang)

使用Redis做任務佇列(Golang)

        在上篇用純go在本機模擬了下分散式佇列的東西。這裡補上Redis佇列部份。
用Redis做佇列有下面三個問題需解決:

 1. 佇列構建
     使用Redis的RPUSH/LPOP來解決

 2. 引數傳遞/解析 
  客戶端將JOSN引數存入Redis,Server端取出後解析還原。

 3. 連線池

      redigo支援Redis連線池

下面程式碼就是具體解決實現:

//Redis做後臺任務佇列
//author: Xiong Chuan Liang
//date: 2015-3-25

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"github.com/garyburd/redigo/redis"
)

func main() {

	r, err := newRedisPool("", "")
	if err != nil {
		fmt.Println(err)
		return
	}

	//將job放入佇列
	r.Enqueue()

	//依次取出兩個Job
	r.GetJob()
	r.GetJob()
}

type RedisPool struct {
	pool *redis.Pool
}

func newRedisPool(server, password string) (*RedisPool, error) {

	if server == "" {
		server = ":6379"
	}

	pool := &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}

			if password != "" {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}

	return &RedisPool{pool}, nil
}

type Job struct {
	Class string        `json:"Class"`
	Args  []interface{} `json:"Args"`
}

//模擬客戶端
func (r *RedisPool) Enqueue() error {

	c := r.pool.Get()
	defer c.Close()

	j := &Job{}
	j.Class = "mail"
	j.Args = append(j.Args, "
[email protected]
", "", "body", 2, true) j2 := &Job{} j2.Class = "Log" j2.Args = append(j2.Args, "ccc.log", "ddd.log", []int{222, 333}) for _, v := range []*Job{j, j2} { b, err := json.Marshal(v) if err != nil { return err } _, err = c.Do("rpush", "queue", b) if err != nil { return err } } fmt.Println("[Enqueue()] succeed!") return nil } //模擬Job Server func (r *RedisPool) GetJob() error { count, err := r.QueuedJobCount() if err != nil || count == 0 { return errors.New("暫無Job.") } fmt.Println("[GetJob()] Jobs count:", count) c := r.pool.Get() defer c.Close() for i := 0; i < int(count); i++ { reply, err := c.Do("LPOP", "queue") if err != nil { return err } var j Job decoder := json.NewDecoder(bytes.NewReader(reply.([]byte))) if err := decoder.Decode(&j); err != nil { return err } fmt.Println("[GetJob()] ", j.Class, " : ", j.Args) } return nil } func (r *RedisPool) QueuedJobCount() (int, error) { c := r.pool.Get() defer c.Close() lenqueue, err := c.Do("llen", "queue") if err != nil { return 0, err } count, ok := lenqueue.(int64) if !ok { return 0, errors.New("型別轉換錯誤!") } return int(count), nil } /* 執行結果: [Enqueue()] succeed! [GetJob()] Jobs count: 2 [GetJob()] mail : [
[email protected]
body 2 true] [GetJob()] Log : [ccc.log ddd.log [222 333]] [[email protected] src]# */
    可以看到Go已能取得引數。都是些最基礎的東西。

MAIL: [email protected]

BLOG: http://blog.csdn.net