Fix race condition that causes the test flaky. - #36235
Conversation
|
Assigning reviewers: R: @jrmccluskey for label go. Note: If you would like to opt out of this review, comment Available commands:
The PR bot will only process comments in the main thread (not review comments). |
lostluck
left a comment
There was a problem hiding this comment.
Seems reasonable. Have you run this 100x with the race detector on and off to ensure it's deflaked?
Alternatively (or simultaneously), there's a gap we discussed offline about how the job.sendState function works. If we have it return the "decided" state, some of the other checks would be less racy as well.
| ) | ||
| var jobIsRunning bool | ||
| for range maxRetries { | ||
| stateResp, err := undertest.GetState(ctx, &jobpb.GetJobStateRequest{JobId: runResp.GetJobId()}) |
There was a problem hiding this comment.
I'd use the streaming version of the call, not the one-off . Then there's less dynamic waiting for things to happen for up to a second.
There was a problem hiding this comment.
I have replaced this waiting part with a waitgroup, which is more concise and clear.
Yes I tried the fix 1000x with the race detector and do not see any failure.
If we change job.sendState to return a state after processing through a state machine, then a lot of exported apis in job.go, such as the following, would need changing to returning the state. Is that ok? func (j *Job) Start() {
j.sendState(jobpb.JobState_STARTING)
}
// Running indicates that the job is executing.
func (j *Job) Running() {
j.sendState(jobpb.JobState_RUNNING)
}
// Done indicates that the job completed successfully.
func (j *Job) Done() {
j.sendState(jobpb.JobState_DONE)
}
// Canceling indicates that the job is canceling.
func (j *Job) Canceling() {
j.sendState(jobpb.JobState_CANCELLING)
} |
Mechanically, there's no problem with it, as these are internal packages, and we can change all the callers. But there's not need to change all the callers right away, just for the cancellation call where it appears to matter, and we look up the state immediately. Most other calls are never inspecting the job status immediately afterwards, setting and forgetting as the job progresses through the pipeline execution. It's OK not to change the other calls. |
…ting waitgroup for clarity.
Let's use this PR to deflake a test first. I opened a new task for adding the state machine in sendState: 36241. |
The Precommit Go test has been flaky (https://github.com/apache/beam/actions/runs/17922206057/job/50959740198).
The error is related to
TestServer_RunThenCanceland the error message is below.After some investigation, I found it is related to a race condition between the main thread and the Server go routine.
The cancel call is made after the server starts to run.
beam/sdks/go/pkg/beam/runners/prism/internal/jobservices/server_test.go
Lines 114 to 124 in 08b0572
The race condition occurs in the following order:
undertest.Run()to the point of setting the state to RUNNING.undertest.Cancel.job.CancelFn(ErrCancel)is called, the server go rountine finishes the check on Line 89 and return.beam/sdks/go/pkg/beam/runners/prism/internal/jobservices/server_test.go
Lines 86 to 94 in 08b0572
In this PR, I added the logic to wait until the context is done before checking the cause.
Furthermore, after fixing the previous race condition, there is yet another: when
undertest.Cancelis called, it is not guaranteed that the job reaches the RUNNING state. So additional logic is needed to wait for the RUNNING state before triggering the cancel.