fix(test): eliminate two wfengine integration flakes (bookshelf-7dfl + bookshelf-19lt) #397
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "bd-bookshelf-7dfl"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Two flaky integration tests in
internal/wfenginehave been burning ~6 CI re-triggers per day on unrelated PRs.Flake 1:
diag_accessor_integration_test.go— WaitForCompletion hang (bookshelf-7dfl)Root cause:
DeferCleanupis LIFO. The test registeredengine.Stop()andcancel()as separate entries, soStop()ran beforecancel().WaitForCompletionblocks until the worker's context is cancelled and all poller goroutines exit; calling it beforecancel()meant waiting for the full 3-second context timeout plus the 30-secondpoll()long-poll timeout. On a loaded CI runner this produced a 9+ minute hang (and job failure by overall CI timeout).Fix: Combined
cancel()andengine.Stop()into a singleDeferCleanupclosure that cancels the context first, then callsStop(). Pollers exit immediately on cancel;WaitForCompletionreturns in milliseconds.Flake 2:
bulk_workflow_test.go:601— tester panic under CPU starvation (bookshelf-19lt)Root cause: The go-workflows tester has a hardcoded 10-second idle-panic timer (
tester.go:458). Under CPU starvation on a single-core CI runner, the callback delivering the activity-failure result was delayed past 10 seconds, causing the tester topanic("workflow blocked?")attester.go:470.Fix: Pass
tester.WithTestTimeout(60*time.Second)to theBulkMetadataWorkflowNewWorkflowTestercall. The tester API provides this option exactly for slow/loaded environments.Test plan
make test— greenmake integration— greenmake coverage— 100.0% gate passesgo vet+golangci-lint --new-from-rev=origin/main ./internal/wfengine/...— 0 issuesgo build -tags e2e ./e2e/...— builds cleanEngine.ListInstances+Engine.GetInstanceStateintegration specs with GOMAXPROCS=2 — 260 executions, 0 failuresBulkMetadataWorkflow(all 5 specs) with GOMAXPROCS=2 — 250 executions, 0 failuresCloses beads bookshelf-7dfl and bookshelf-19lt on merge.
3672e586c3a16ffede65Security Review — bd-bookshelf-7dfl (PR #397)
Diff scope:
internal/wfengine/bulk_workflow_test.go,internal/wfengine/diag_accessor_integration_test.go— two test files only.Findings
No security findings. Specifically verified:
_test.gosuffix).WithTestTimeout(60*time.Second)) and DeferCleanup ordering (LIFO consolidation for race-free teardown). Neither change relaxes any security boundary.cancel()beforeengine.Stop(), which is more correct (stops pollers before waiting on the engine), not less secure.REVIEW VERDICT: 0 blocker, 0 major, 0 minor
Code Review — PR #397 (bookshelf-7dfl + bookshelf-19lt wfengine flake fixes)
Reviewed diff:
origin/main...origin/bd-bookshelf-7dfl(heada16ffede). CI green. Test-only changes verified.Claim 1 —
diag_accessor_integration_test.go: DeferCleanup LIFO ordering (bookshelf-7dfl)Verified correct. The fix combines
cancel()+engine.Stop()into a singleDeferCleanupclosure, withcancel()first. This is the right ordering: cancelling the context stops the pollers soengine.Stop()/WaitForCompletioncan return promptly instead of blocking until the 3-second timeout expires with pollers still active.Sibling-bug sweep: all other integration tests that call
StartWorkeralready use a single combined closure pattern:engine_integration_test.golines 138–146, 217–225: combinedcancel()+Stop()in one closure ✓scan_integration_test.golines 166–179: combinedcancel()+Stop()✓The second
Describeblock indiag_accessor_integration_test.go(line 119) keeps a standaloneDeferCleanup(func() { _ = engine.Stop() })— this is NOT the same bug. That block does not callStartWorkerand has no context to cancel, so no combined closure is needed.No split-DeferCleanup survivors remain in the package.
Claim 2 —
bulk_workflow_test.go:WithTestTimeout(60s)onBulkMetadataWorkflowtester (bookshelf-19lt)Verified correct. The timeout is applied to the single
NewWorkflowTestercall in theBulkMetadataWorkflowDescribe block (line 573), which is the only tester that covers both the success path AND the failure path (viastubErr = errors.New("save failed")in a nestedContext). The 60s headroom matches the CI comment: the activity-failure path must propagate through the go-workflows event loop before the default 10s idle panic fires on a loaded single-core runner.Missed-sibling scan of all
NewWorkflowTestercall sites with failure paths:Other workflow testers that exercise failure paths (a failing activity returning an error):
EnrichWorkflow(simple_workflows_test.go:177):stubErr = errors.New("enrich error")→ still on default 10s.DeleteBooksWorkflow(simple_workflows_test.go:264):stubErr = errors.New("delete failed")→ still on default 10s.TemplateGenerateWorkflow(simple_workflows_test.go:76):stubErr = errors.New("template error")→ still on default 10s.LibraryScanWorkflow — list activity error(scan_workflow_test.go:194):errors.New("list db failure")→ still on default 10s.BulkCoversWorkflow — list activity error(bulk_workflow_test.go:184):errors.New("list failure")→ still on default 10s.BulkEnrichWorkflow — list activity error(bulk_workflow_test.go:400):errors.New("db timeout")→ still on default 10s.The question is why
BulkMetadataWorkflowwas singled out. Looking at the bead description: "bookshelf-19lt" specifically targeted the metadata-workflow CI failure. The other failure-path testers listed above have presumably not flaked in CI under the same conditions — they may exercise shallower event-loop paths or simpler retry configurations. Without evidence that they share the same flake pattern, extending the timeout to them speculatively would be untargeted noise.Assessment: not a missed sibling in the same category as the fix. The fix is targeted to the known flaking test. Other failure-path testers that haven't flaked in CI do not require treatment on this PR.
Standard checks
Skip, no removedExpect. ✓NodeTimeout/SpecTimeoutunchanged; only per-tester idle timeout increased for the specific flaking tester. ✓time.Sleep(200 * time.Millisecond)indiag_accessor_integration_test.goline 64 predates this PR. ✓REVIEW VERDICT: 0 blocker, 0 major, 0 minor