Skip to content

Commit 1eb83c2

Browse files
A small fix to avoid deadlock that can happen as mentioned in issue #3682 (#3715)
Signed-off-by: Anand Rajagopal <[email protected]>
1 parent d85bef2 commit 1eb83c2

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

provider/mem/mem.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ func max(a, b int) int {
151151
func (a *Alerts) Subscribe() provider.AlertIterator {
152152
a.mtx.Lock()
153153
defer a.mtx.Unlock()
154-
155154
var (
156155
done = make(chan struct{})
157156
alerts = a.alerts.List()

provider/mem/mem_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,63 @@ func TestAlertsSubscribePutStarvation(t *testing.T) {
135135
}
136136
}
137137

138+
func TestDeadLock(t *testing.T) {
139+
t0 := time.Now()
140+
t1 := t0.Add(5 * time.Second)
141+
142+
marker := types.NewMarker(prometheus.NewRegistry())
143+
// Run gc every 5 milliseconds to increase the possibility of a deadlock with Subscribe()
144+
alerts, err := NewAlerts(context.Background(), marker, 5*time.Millisecond, noopCallback{}, log.NewNopLogger(), nil)
145+
if err != nil {
146+
t.Fatal(err)
147+
}
148+
alertsToInsert := []*types.Alert{}
149+
for i := 0; i < 200+1; i++ {
150+
alertsToInsert = append(alertsToInsert, &types.Alert{
151+
Alert: model.Alert{
152+
// Make sure the fingerprints differ
153+
Labels: model.LabelSet{"iteration": model.LabelValue(strconv.Itoa(i))},
154+
Annotations: model.LabelSet{"foo": "bar"},
155+
StartsAt: t0,
156+
EndsAt: t1,
157+
GeneratorURL: "http://example.com/prometheus",
158+
},
159+
UpdatedAt: t0,
160+
Timeout: false,
161+
})
162+
}
163+
164+
if err := alerts.Put(alertsToInsert...); err != nil {
165+
t.Fatal("Unable to add alerts")
166+
}
167+
done := make(chan bool)
168+
169+
// call subscribe repeatedly in a goroutine to increase
170+
// the possibility of a deadlock occurring
171+
go func() {
172+
tick := time.NewTicker(10 * time.Millisecond)
173+
defer tick.Stop()
174+
stopAfter := time.After(1 * time.Second)
175+
for {
176+
select {
177+
case <-tick.C:
178+
alerts.Subscribe()
179+
case <-stopAfter:
180+
done <- true
181+
break
182+
}
183+
}
184+
}()
185+
186+
select {
187+
case <-done:
188+
// no deadlock
189+
alerts.Close()
190+
case <-time.After(10 * time.Second):
191+
t.Error("Deadlock detected")
192+
}
193+
}
194+
138195
func TestAlertsPut(t *testing.T) {
139196
marker := types.NewMarker(prometheus.NewRegistry())
140197
alerts, err := NewAlerts(context.Background(), marker, 30*time.Minute, noopCallback{}, log.NewNopLogger(), nil)

store/store.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,14 @@ func (a *Alerts) Run(ctx context.Context, interval time.Duration) {
7171

7272
func (a *Alerts) gc() {
7373
a.Lock()
74-
defer a.Unlock()
75-
7674
var resolved []*types.Alert
7775
for fp, alert := range a.c {
7876
if alert.Resolved() {
7977
delete(a.c, fp)
8078
resolved = append(resolved, alert)
8179
}
8280
}
81+
a.Unlock()
8382
a.cb(resolved)
8483
}
8584

0 commit comments

Comments
 (0)