11package main
22
33import (
4+ "encoding/json"
45 "sync"
6+ "time"
57
68 "github.com/Sirupsen/logrus"
79 "github.com/garyburd/redigo/redis"
810 "github.com/gorilla/websocket"
11+ "github.com/pkg/errors"
912 "github.com/satori/go.uuid"
1013)
1114
@@ -14,12 +17,36 @@ const (
1417 Channel = "chat"
1518)
1619
20+ var (
21+ waitingMessage , availableMessage []byte
22+ waitSleep = time .Second * 10
23+ )
24+
25+ func init () {
26+ var err error
27+ waitingMessage , err = json .Marshal (message {
28+ Handle : "system" ,
29+ Text : "Waiting for redis to be available. Messaging won't work until redis is available" ,
30+ })
31+ if err != nil {
32+ panic (err )
33+ }
34+ availableMessage , err = json .Marshal (message {
35+ Handle : "system" ,
36+ Text : "Redis is now available & messaging is now possible" ,
37+ })
38+ if err != nil {
39+ panic (err )
40+ }
41+ }
42+
1743// redisReceiver receives messages from Redis and broadcasts them to all
1844// registered websocket connections that are Registered.
1945type redisReceiver struct {
20- pool * redis.Pool
21- sync.Mutex // Protects the conns map
22- conns map [string ]* websocket.Conn
46+ pool * redis.Pool
47+
48+ mu sync.Mutex
49+ conns map [string ]* websocket.Conn
2350}
2451
2552// newRedisReceiver creates a redisReceiver that will use the provided
@@ -31,9 +58,15 @@ func newRedisReceiver(pool *redis.Pool) redisReceiver {
3158 }
3259}
3360
61+ func (rr * redisReceiver ) wait (_ time.Time ) error {
62+ rr .broadcast (waitingMessage )
63+ time .Sleep (waitSleep )
64+ return nil
65+ }
66+
3467// run receives pubsub messages from Redis after establishing a connection.
3568// When a valid message is received it is broadcast to all connected websockets
36- func (rr * redisReceiver ) run () {
69+ func (rr * redisReceiver ) run () error {
3770 l := log .WithField ("channel" , Channel )
3871 conn := rr .pool .Get ()
3972 defer conn .Close ()
@@ -54,7 +87,7 @@ func (rr *redisReceiver) run() {
5487 "count" : v .Count ,
5588 }).Println ("Redis Subscription Received" )
5689 case error :
57- l . WithField ( "err" , v ). Error ( "Error while subscribed to Redis channel" )
90+ return errors . Wrap ( v , "Error while subscribed to Redis channel" )
5891 default :
5992 l .WithField ("v" , v ).Info ("Unknown Redis receive during subscription" )
6093 }
@@ -65,8 +98,8 @@ func (rr *redisReceiver) run() {
6598// If an error occurs while writting a message to a websocket connection it is
6699// closed and deregistered.
67100func (rr * redisReceiver ) broadcast (data []byte ) {
68- rr .Mutex .Lock ()
69- defer rr .Mutex .Unlock ()
101+ rr .mu .Lock ()
102+ defer rr .mu .Unlock ()
70103 for id , conn := range rr .conns {
71104 if err := conn .WriteMessage (websocket .TextMessage , data ); err != nil {
72105 log .WithFields (logrus.Fields {
@@ -84,17 +117,17 @@ func (rr *redisReceiver) broadcast(data []byte) {
84117// identifier for the connection. This identifier can be used to deregister the
85118// connection later
86119func (rr * redisReceiver ) register (conn * websocket.Conn ) string {
87- rr .Mutex .Lock ()
88- defer rr .Mutex .Unlock ()
120+ rr .mu .Lock ()
121+ defer rr .mu .Unlock ()
89122 id := uuid .NewV4 ().String ()
90123 rr .conns [id ] = conn
91124 return id
92125}
93126
94127// deRegister the connection by closing it and removing it from our list.
95128func (rr * redisReceiver ) deRegister (id string ) {
96- rr .Mutex .Lock ()
97- defer rr .Mutex .Unlock ()
129+ rr .mu .Lock ()
130+ defer rr .mu .Unlock ()
98131 conn , ok := rr .conns [id ]
99132 if ok {
100133 conn .Close ()
@@ -111,24 +144,32 @@ type redisWriter struct {
111144func newRedisWriter (pool * redis.Pool ) redisWriter {
112145 return redisWriter {
113146 pool : pool ,
114- messages : make (chan []byte ),
147+ messages : make (chan []byte , 10000 ),
115148 }
116149}
117150
118151// run the main redisWriter loop that publishes incoming messages to Redis.
119- func (rw * redisWriter ) run () {
152+ func (rw * redisWriter ) run () error {
120153 conn := rw .pool .Get ()
121154 defer conn .Close ()
122155
123156 for data := range rw .messages {
124- l := log .WithField ("data" , data )
125- if err := conn .Send ("PUBLISH" , Channel , data ); err != nil {
126- l .WithField ("err" , err ).Fatalf ("Unable to publish message to Redis" )
127- }
128- if err := conn .Flush (); err != nil {
129- l .WithField ("err" , err ).Fatalf ("Unable to flush published message to Redis" )
157+ if err := writeToRedis (conn , data ); err != nil {
158+ rw .publish (data ) // attempt to redeliver later
159+ return err
130160 }
131161 }
162+ return nil
163+ }
164+
165+ func writeToRedis (conn redis.Conn , data []byte ) error {
166+ if err := conn .Send ("PUBLISH" , Channel , data ); err != nil {
167+ return errors .Wrap (err , "Unable to publish message to Redis" )
168+ }
169+ if err := conn .Flush (); err != nil {
170+ return errors .Wrap (err , "Unable to flush published message to Redis" )
171+ }
172+ return nil
132173}
133174
134175// publish to Redis via channel.
0 commit comments