Ejemplo n.º 1
0
func (s *Storage) PubSub(redis_server, redis_auth, node_name string) {
	pool := &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", redis_server)
			if err != nil {
				return nil, err
			}
			if redis_auth != "" {
				if _, err := c.Do("AUTH", redis_auth); 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
		},
	}

	pubsub_channel := "solocounter"
	if node_name == "" {
		node_name = randomString()
	}

	go func() {
		var conn redis.Conn
		var psc redis.PubSubConn

		__connect__ := func() {
			conn = pool.Get()
			psc = redis.PubSubConn{conn}
			psc.Subscribe(pubsub_channel)
		}
		__connect__()
		defer conn.Close()

		for {
			switch v := psc.Receive().(type) {
			case redis.Message:
				if v.Channel == pubsub_channel {
					var entry RedisEntry
					err := json.Unmarshal(v.Data, &entry)
					if err != nil {
						log.Println("[error][json][unmarshal] : " + err.Error())
					} else {
						if entry.Node != node_name {
							if s.Verbose {
								log.Printf("[push][redis] %s, %s, %d", entry.Path, entry.Address, entry.Time)
							}
							s.get(entry.Path).add(entry.Address, entry.Time)
						}
					}
				}
			case redis.Subscription:
				fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)
			case error:
				switch v.Error() {
				case fmt.Sprintf("dial tcp %s: connection refused", redis_server):
					fallthrough
				case "EOF":
					log.Println("[error][redis][subscribe] : " + v.Error() + " -> will reconnect 1 second later")
					time.Sleep(time.Second * REDIS_RECONNECT_INTERVAL)
					__connect__()
				default:
					log.Println("[error][redis][subscribe] : " + v.Error())
				}
			}
		}
	}()

	s.c = make(chan RedisEntry, CHAN_CAPACITY_REDIS_ENTRY)
	go func() {
		conn := pool.Get()
		defer conn.Close()

		for {
			select {
			case entry := <-s.c:
				entry.Node = node_name
				b, err := json.Marshal(entry)
				if err != nil {
					log.Println("[error][json][marshal] : " + err.Error())
				} else {
					_, err := conn.Do("PUBLISH", pubsub_channel, b)
					if err != nil {
						log.Println("[error][redis][publish] : " + err.Error())
					}
				}
			}
		}
	}()
}
Ejemplo n.º 2
0
func TestPushed(t *testing.T) {
	pc, err := redistest.Dial()
	if err != nil {
		t.Fatalf("error connection to database, %v", err)
	}
	defer pc.Close()

	nc, err := net.Dial("tcp", ":6379")
	if err != nil {
		t.Fatal(err)
	}
	defer nc.Close()
	nc.SetReadDeadline(time.Now().Add(4 * time.Second))

	c := redis.PubSubConn{Conn: redis.NewConn(nc, 0, 0)}

	c.Subscribe("c1")
	expectPushed(t, c, "Subscribe(c1)", redis.Subscription{Kind: "subscribe", Channel: "c1", Count: 1})
	c.Subscribe("c2")
	expectPushed(t, c, "Subscribe(c2)", redis.Subscription{Kind: "subscribe", Channel: "c2", Count: 2})
	c.PSubscribe("p1")
	expectPushed(t, c, "PSubscribe(p1)", redis.Subscription{Kind: "psubscribe", Channel: "p1", Count: 3})
	c.PSubscribe("p2")
	expectPushed(t, c, "PSubscribe(p2)", redis.Subscription{Kind: "psubscribe", Channel: "p2", Count: 4})
	c.PUnsubscribe()
	expectPushed(t, c, "Punsubscribe(p1)", redis.Subscription{Kind: "punsubscribe", Channel: "p1", Count: 3})
	expectPushed(t, c, "Punsubscribe()", redis.Subscription{Kind: "punsubscribe", Channel: "p2", Count: 2})

	pc.Do("PUBLISH", "c1", "hello")
	expectPushed(t, c, "PUBLISH c1 hello", redis.Message{Channel: "c1", Data: []byte("hello")})

	c.Ping("hello")
	expectPushed(t, c, `Ping("hello")`, redis.Pong{"hello"})

	c.Conn.Send("PING")
	c.Conn.Flush()
	expectPushed(t, c, `Send("PING")`, redis.Pong{})
}
Ejemplo n.º 3
0
// Applications can receive pushed messages from one goroutine and manage subscriptions from another goroutine.
func ExamplePubSubConn() {
	c, err := dial()
	if err != nil {
		panic(err)
	}
	defer c.Close()
	var wg sync.WaitGroup
	wg.Add(2)

	psc := redis.PubSubConn{Conn: c}

	// This goroutine receives and prints pushed notifications from the server.
	// The goroutine exits when the connection is unsubscribed from all
	// channels or there is an error.
	go func() {
		defer wg.Done()
		for {
			switch n := psc.Receive().(type) {
			case redis.Message:
				fmt.Printf("Message: %s %s\n", n.Channel, n.Data)
			case redis.PMessage:
				fmt.Printf("PMessage: %s %s %s\n", n.Pattern, n.Channel, n.Data)
			case redis.Subscription:
				fmt.Printf("Subscription: %s %s %d\n", n.Kind, n.Channel, n.Count)
				if n.Count == 0 {
					return
				}
			case error:
				fmt.Printf("error: %v\n", n)
				return
			}
		}
	}()

	// This goroutine manages subscriptions for the connection.
	go func() {
		defer wg.Done()

		psc.Subscribe("example")
		psc.PSubscribe("p*")

		// The following function calls publish a message using another
		// connection to the Redis server.
		publish("example", "hello")
		publish("example", "world")
		publish("pexample", "foo")
		publish("pexample", "bar")

		// Unsubscribe from all connections. This will cause the receiving
		// goroutine to exit.
		psc.Unsubscribe()
		psc.PUnsubscribe()
	}()

	wg.Wait()

	// Output:
	// Subscription: subscribe example 1
	// Subscription: psubscribe p* 2
	// Message: example hello
	// Message: example world
	// PMessage: p* pexample foo
	// PMessage: p* pexample bar
	// Subscription: unsubscribe example 1
	// Subscription: punsubscribe p* 0
}
Ejemplo n.º 4
0
func expectPushed(t *testing.T, c redis.PubSubConn, message string, expected interface{}) {
	actual := c.Receive()
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("%s = %v, want %v", message, actual, expected)
	}
}