-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
silences: avoid deadlock #995
Conversation
silence/silence_test.go
Outdated
require.Equal(t, want.data, s.st.data, "Unexpected silence state") | ||
|
||
// GossipBroadcast is called in a gorountine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: goroutine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
Calling gossip.GossipBroadcast() will cause a deadlock if there is a currently executing OnBroadcast* function. See prometheus#982
LGTM |
s.gossip.GossipBroadcast(st) | ||
// setSilence() is called with s.mtx locked, which can produce | ||
// a deadlock if we call GossipBroadcast from here. | ||
go s.gossip.GossipBroadcast(st) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests still pass when I remove the go
here. The tests should fail without the inclusion of this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
once those changes are made to the test, good to merge. Thanks for your patience!
silence/silence_test.go
Outdated
require.NoError(t, s.setSilence(sil)) | ||
require.True(t, called, "GossipBroadcast was not called") | ||
s.mtx.Unlock() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this test passes because of the go
, if someone were to remove the go
, this deadlocks and the timeout in the select
below is never called. If you re-arrange the code like below, then we have a passing test with your code 🙌 , and if someone removes the go
, it will fail instead of locking up:
diff --git a/silence/silence_test.go b/silence/silence_test.go
index 420a78c..eed4060 100644
--- a/silence/silence_test.go
+++ b/silence/silence_test.go
@@ -213,11 +213,11 @@ func TestSilencesSetSilence(t *testing.T) {
}
// setSilence() is always called with s.mtx locked()
- s.mtx.Lock()
- require.NoError(t, s.setSilence(sil))
- s.mtx.Unlock()
-
- require.Equal(t, want.data, s.st.data, "Unexpected silence state")
+ go func() {
+ s.mtx.Lock()
+ require.NoError(t, s.setSilence(sil))
+ s.mtx.Unlock()
+ }()
// GossipBroadcast is called in a goroutine.
select {
@@ -225,6 +225,8 @@ func TestSilencesSetSilence(t *testing.T) {
case <-time.After(1 * time.Second):
t.Fatal("GossipBroadcast was not called")
}
+
+ require.Equal(t, want.data, s.st.data, "Unexpected silence state")
}
func TestSilenceSet(t *testing.T) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
…stemd 239 (prometheus#995) Signed-off-by: xginn8 <mamcgi@gmail.com>
Calling gossip.GossipBroadcast() will cause a deadlock if
there is a currently executing OnBroadcast* function.
See #982