Repository navigation
chore(safego): remove unused WithRestartTimeout (fixes data race) - #1465
kotwal-itpro wants to merge 1 commit into
Conversation
5de640a to
7e33052
Compare
|
Hey team, just checking in on this one — rebased against latest newjitsu today (was quite a way behind since safego hadn't been touched upstream). CI should re-run. The fix captures restartTimeout at spawn time to eliminate the data race in WithRestartTimeout. safego is called in 20+ production paths across bulker, ingest, kafkabase, sync-controller, bulkerapp, and eventslog, so it seemed worth getting right. Happy to change the approach if you'd prefer a different sync primitive. Thanks! |
7e33052 to
0bb049f
Compare
|
Rebased onto latest newjitsu to keep this current and mergeable (had drifted since the last sync). No changes to the fix itself — diff is identical, just replayed cleanly on top of recent upstream changes. CI should re-run on the new head. |
0bb049f to
db98d43
Compare
|
@absorbb @sahiltyagi-jitsu — would one of you have a few minutes to take a look at this? It's a small, self-contained fix (2 files in I've rebased onto the latest |
|
@kotwal-itpro |
db98d43 to
19a12b4
Compare
|
@absorbb good call, thanks. I've updated the PR to simply remove |
WithRestartTimeout mutated Execution.restartTimeout after the goroutine had already started, racing with the recover handler that reads it. Nothing in the codebase calls it except its own test, so remove it instead of patching the race. The test now constructs the Execution directly with a short restart timeout and uses an atomic counter so it passes go test -race. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
19a12b4 to
cbdef22
Compare
Problem
Execution.WithRestartTimeoutmutatesexec.restartTimeoutfrom the caller's goroutine, while the spawned goroutine's panic-recoverydeferreads that same field on restart. When a caller uses the documentedRunWithRestart(f).WithRestartTimeout(t)builder pattern (as safego's ownTestHandlePanicAndRestartdid), the goroutine is already running by the time the setter fires — any panic in the interim races the write.go test -race ./bulker/jitsubase/safego/reproduces it deterministically on currentnewjitsu:safego.RunWithRestart/safego.Runare called in 20+ production paths acrossbulker/,ingest/,kafkabase/,sync-controller/,bulkerapp/,eventslog/, andjitsubase/, so the primitive is load-bearing. No current production caller happens to chainWithRestartTimeout, so the race does not fire in shipped code — but the pattern is publicly exported and documented, so any future caller (or a copy-paste from the existing test) trips it.Fix (backward compatible)
RunWithRestartTimeout(f func(), timeout time.Duration) *Execution— sets the timeout before the goroutine spawns, eliminating the need for the mutating builder pattern in the common case.run()capturesrestartTimeoutinto a function-local at spawn time, so a subsequent mutation via the deprecated setter (or any future mutation of the sharedExecution) cannot race the goroutine's recovery handler.WithRestartTimeoutretained for source-level backward compatibility and marked with aDeprecated:doc comment pointing callers at the race-free constructor.Test
Updates
TestHandlePanicAndRestartto use the new constructor and anatomic.Int32counter (the previous plain-int shared counter was itself flagged by-race).Verified
go test -race -count=5 ./bulker/jitsubase/safego/— 5/5 pass (was consistently failing before)go build ./...clean onjitsubase,kafkabase,bulkerlib,bulkerapp,ingest,sync-controllerRun,RunWithRestart, andWithRestartTimeoutall keep their signatures; newRunWithRestartTimeoutis additive