-
Notifications
You must be signed in to change notification settings - Fork 303
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
Change healthchecksl4 sync mechanism #1812
Change healthchecksl4 sync mechanism #1812
Conversation
/assign @kl52752 |
16f9a9b
to
27efd4c
Compare
@@ -70,7 +69,6 @@ func newServiceController(t *testing.T, fakeGCE *gce.Cloud) *L4Controller { | |||
for _, n := range nodes { | |||
ctx.NodeInformer.GetIndexer().Add(n) | |||
} | |||
healthchecksl4.Fake(ctx.Cloud, ctx) |
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.
So right now all test for controllers are creating the health checks with shared mutex because it is created in NewHandler function. Is it desired?
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.
Before this PR, NewHandler creates L4 with "synced" healthchecks, and then in all the tests, after NewHandler(), we override them with "Fake" health checks, which are supposed to be not synced. This approach is still questionable, but to fix it, it needs bigger refactoring
but still, if you look at the current Fake code
func Fake(cloud *gce.Cloud, recorderFactory events.RecorderProducer) *l4HealthChecks {
instance = &l4HealthChecks{
cloud: cloud,
recorderFactory: recorderFactory,
hcProvider: healthchecksprovider.NewHealthChecks(cloud, meta.VersionGA),
}
return instance
}
mutex sharedResourcesLock sync.Mutex
created automatically, cause it is member of struct by "value", so it is suppose to be "unsynced" and it's own for each of result of Fake()
But, now, if multiple tests running in parallel, it can be a race condition in Fake(), if 2 goroutines execute at first
instance = &l4HealthChecks{
cloud: cloud,
recorderFactory: recorderFactory,
hcProvider: healthchecksprovider.NewHealthChecks(cloud, meta.VersionGA),
}
then return instance
will return the same instance for both of them
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.
but in controller test you don't use Fake for health check you just depend on the controller to create it's own l4 hander and it is using default function and here.
ANd in test code you create for every controller different fakeGCE
And for me there is no race condition unless test use the same fakeGCE (It probably is within one test not across the tests which run in parallel).
ANd for me it looks like all test are locked with the same mutex and use different fakeGCE.
Does it make sense to you?
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.
You are right, just seems that l4controller_test and l4netlbcontroller_test don't use Parallel (cause they check "global" metrics") so it will not help if the mutex of health checks will be not shared
27efd4c
to
6c3c4f0
Compare
/assign cezarygerard |
see my 2 small comments |
pkg/healthchecksl4/healthchecksl4.go
Outdated
recorderFactory: recorderFactory, | ||
hcProvider: healthchecksprovider.NewHealthChecks(cloud, meta.VersionGA), | ||
// FakeNotSynced creates instance of l4HealthChecks with independent lock. Use for test only. | ||
func FakeNotSynced(cloud *gce.Cloud, recorder record.EventRecorder) *l4HealthChecks { |
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.
why not call this just Fake?
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.
Okay, I renamed to Fake, difference is not that big,
I just thought that it is so similar to just normal l4HealthChecks, that it is not that clear, what is "fake" here
// instance is a singleton instance, created by Initialize | ||
instance *l4HealthChecks | ||
// sharedLock used to prevent race condition between shared health checks and firewalls. | ||
sharedLock = &sync.Mutex{} |
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.
So this variable should only exist once? I like 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.
yep, it is initialised in the very beginning of execution, and then shared between every healthchecksl4
Removed shared global struct, instead only use shared mutex For fake, return healthchecks instance with independent mutex
6c3c4f0
to
5af9549
Compare
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: cezarygerard, panslava The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Removed shared global struct, instead only use shared mutex
for fake, return healthchecks instance with independent mutex
I also want to make our package pass go test -race, and current fake approach makes it fail