Skip to content

Commit

Permalink
A small fix to avoid deadlock that can happen as mentioned in issue p…
Browse files Browse the repository at this point in the history
  • Loading branch information
rajagopalanand committed Feb 8, 2024
1 parent d4deb6d commit c2d8ae2
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 3 deletions.
6 changes: 3 additions & 3 deletions provider/mem/mem.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,13 @@ func max(a, b int) int {
// resolved and successfully notified about.
// They are not guaranteed to be in chronological order.
func (a *Alerts) Subscribe() provider.AlertIterator {
alerts := a.alerts.List()
a.mtx.Lock()
defer a.mtx.Unlock()

var (
done = make(chan struct{})
alerts = a.alerts.List()
ch = make(chan *types.Alert, max(len(alerts), alertChannelLength))
done = make(chan struct{})
ch = make(chan *types.Alert, max(len(alerts), alertChannelLength))
)

for _, a := range alerts {
Expand Down
56 changes: 56 additions & 0 deletions provider/mem/mem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,62 @@ func TestAlertsSubscribePutStarvation(t *testing.T) {
}
}

func TestDeadLock(t *testing.T) {
t0 := time.Now()
t1 := t0.Add(5 * time.Second)

marker := types.NewMarker(prometheus.NewRegistry())
// Run gc every 5 milliseconds to increase the possibility of a deadlock with Subscribe()
alerts, err := NewAlerts(context.Background(), marker, 5*time.Millisecond, noopCallback{}, log.NewNopLogger(), nil)
if err != nil {
t.Fatal(err)
}
alertsToInsert := []*types.Alert{}
for i := 0; i < 200+1; i++ {
alertsToInsert = append(alertsToInsert, &types.Alert{
Alert: model.Alert{
// Make sure the fingerprints differ
Labels: model.LabelSet{"iteration": model.LabelValue(strconv.Itoa(i))},
Annotations: model.LabelSet{"foo": "bar"},
StartsAt: t0,
EndsAt: t1,
GeneratorURL: "http://example.com/prometheus",
},
UpdatedAt: t0,
Timeout: false,
})
}

if err := alerts.Put(alertsToInsert...); err != nil {
t.Fatal("Unable to add alerts")
}
done := make(chan bool)

// call subscribe repeatedly in a goroutine to increase
// the possibility of a deadlock occurring
go func() {
tick := time.NewTicker(10 * time.Millisecond)
defer tick.Stop()
stopAfter := time.After(1 * time.Second)
for {
select {
case <-tick.C:
alerts.Subscribe()
case <-stopAfter:
done <- true
break
}
}
}()

select {
case <-done:
// no deadlock
case <-time.After(10 * time.Second):
t.Error("Deadlock detected")
}
}

func TestAlertsPut(t *testing.T) {
marker := types.NewMarker(prometheus.NewRegistry())
alerts, err := NewAlerts(context.Background(), marker, 30*time.Minute, noopCallback{}, log.NewNopLogger(), nil)
Expand Down

0 comments on commit c2d8ae2

Please sign in to comment.