Example #1
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
}
Example #2
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())
					}
				}
			}
		}
	}()
}
Example #3
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)
	}
}