@@ -64,6 +64,7 @@ type redisPeer struct {
64
64
states map [string ]alertingCluster.State
65
65
subs map [string ]* redis.PubSub
66
66
statesMtx sync.RWMutex
67
+ subsMtx sync.RWMutex
67
68
68
69
readyc chan struct {}
69
70
shutdownc chan struct {}
@@ -225,8 +226,10 @@ func newRedisPeer(cfg redisConfig, logger log.Logger, reg prometheus.Registerer,
225
226
p .nodePingDuration = nodePingDuration
226
227
p .nodePingFailures = nodePingFailures
227
228
229
+ p .subsMtx .Lock ()
228
230
p .subs [fullStateChannel ] = p .redis .Subscribe (context .Background (), p .withPrefix (fullStateChannel ))
229
231
p .subs [fullStateChannelReq ] = p .redis .Subscribe (context .Background (), p .withPrefix (fullStateChannelReq ))
232
+ p .subsMtx .Unlock ()
230
233
231
234
go p .heartbeatLoop ()
232
235
go p .membersSyncLoop ()
@@ -461,7 +464,9 @@ func (p *redisPeer) AddState(key string, state alertingCluster.State, _ promethe
461
464
// As we also want to get the state from other nodes, we subscribe to the key.
462
465
sub := p .redis .Subscribe (context .Background (), p .withPrefix (key ))
463
466
go p .receiveLoop (sub )
467
+ p .subsMtx .Lock ()
464
468
p .subs [key ] = sub
469
+ p .subsMtx .Unlock ()
465
470
return newRedisChannel (p , key , p .withPrefix (key ), update )
466
471
}
467
472
@@ -507,17 +512,29 @@ func (p *redisPeer) fullStateReqReceiveLoop() {
507
512
select {
508
513
case <- p .shutdownc :
509
514
return
510
- case data := <- p .subs [fullStateChannelReq ].Channel ():
511
- // The payload of a full state request is the name of the peer that is
512
- // requesting the full state. In case we received our own request, we
513
- // can just ignore it. Redis pub/sub fanouts to all clients, regardless
514
- // if a client was also the publisher.
515
- if data .Payload == p .name {
515
+ default :
516
+ p .subsMtx .RLock ()
517
+ sub , ok := p .subs [fullStateChannelReq ]
518
+ p .subsMtx .RUnlock ()
519
+
520
+ if ! ok {
521
+ time .Sleep (waitForMsgIdle )
516
522
continue
517
523
}
518
- p .fullStateSyncPublish ()
519
- default :
520
- time .Sleep (waitForMsgIdle )
524
+
525
+ select {
526
+ case data := <- sub .Channel ():
527
+ // The payload of a full state request is the name of the peer that is
528
+ // requesting the full state. In case we received our own request, we
529
+ // can just ignore it. Redis pub/sub fanouts to all clients, regardless
530
+ // if a client was also the publisher.
531
+ if data .Payload == p .name {
532
+ continue
533
+ }
534
+ p .fullStateSyncPublish ()
535
+ default :
536
+ time .Sleep (waitForMsgIdle )
537
+ }
521
538
}
522
539
}
523
540
}
@@ -527,10 +544,22 @@ func (p *redisPeer) fullStateSyncReceiveLoop() {
527
544
select {
528
545
case <- p .shutdownc :
529
546
return
530
- case data := <- p .subs [fullStateChannel ].Channel ():
531
- p .mergeFullState ([]byte (data .Payload ))
532
547
default :
533
- time .Sleep (waitForMsgIdle )
548
+ p .subsMtx .RLock ()
549
+ sub , ok := p .subs [fullStateChannel ]
550
+ p .subsMtx .RUnlock ()
551
+
552
+ if ! ok {
553
+ time .Sleep (waitForMsgIdle )
554
+ continue
555
+ }
556
+
557
+ select {
558
+ case data := <- sub .Channel ():
559
+ p .mergeFullState ([]byte (data .Payload ))
560
+ default :
561
+ time .Sleep (waitForMsgIdle )
562
+ }
534
563
}
535
564
}
536
565
}
0 commit comments