Skip to content

fix(coderd/x/chatd): resolve inflight race#26460

Merged
hugodutka merged 1 commit into
mainfrom
hugodutka/inflight-race
Jun 17, 2026
Merged

fix(coderd/x/chatd): resolve inflight race#26460
hugodutka merged 1 commit into
mainfrom
hugodutka/inflight-race

Conversation

@hugodutka

@hugodutka hugodutka commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Using WaitGroup.Go must be synchronized with WaitGroup.Wait according to go docs:

If the WaitGroup is empty, Go must happen before a WaitGroup.Wait.

There were a couple of places in chatd that violated this principle. This was caught as a data race in coder/internal#1599. This PR ensures that all functions that spawn inflight goroutines synchronize with each other.

I also noticed that inflight goroutines may be spawned after the server is closed, which was surprising and looked like a bug. This PR therefore also introduces a mechanism that disallows spawning inflight goroutines after the server is closed, and ensures that any code that tries doing it logs an error.

Closes coder/internal#1599.

Comment thread coderd/x/chatd/chatd.go
}

func (p *Server) clearLastTurnSummaryAsync(
ctx context.Context,
chat database.Chat,
logger slog.Logger,
) {
// This helper runs during processChat cleanup, while processChat is
// still counted in p.inflight. Do not take inflightMu here because

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

processChat does not exist anymore, so I don't think the scenario described here still applies. But even if it did apply, introducing a possible data race does not seem like the right fix to address the problem.

@hugodutka hugodutka force-pushed the hugodutka/inflight-race branch from 08f2a8a to c7a3c78 Compare June 17, 2026 14:53
if server.chatWorker == nil {
return
if server.chatWorker != nil {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we instead allow callers to pass in a parent context instead of hard-coding a timeout here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can, but I'd rather keep this PR scoped to the issue at hand. Would you like me to create a Linear issue for this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figure if it's a real problem then it will show up as a flake.

Comment thread coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd.go
// new goroutines (via inflight.Add) concurrently with Wait,
// which would violate sync.WaitGroup's contract.
func (p *Server) goInflight(f func()) error {
if p.inflightClosed.Load() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just use a RW mutex and do a RLock instead of double check (mutex would protect inflightClosed, not Go per-se, hence read would suffice here.)

@hugodutka hugodutka Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I specifically used an atomic so goInflight can exit early if inflightClosed is true. Otherwise an active drainInflight call - which can be pretty long - would block goInflight calls. I guess you could do that with an RWMutex too if drainInflight also obtained a read lock, but I'm not convinced it's simpler than what we have now.

@hugodutka hugodutka merged commit 684d904 into main Jun 17, 2026
33 checks passed
@hugodutka hugodutka deleted the hugodutka/inflight-race branch June 17, 2026 16:29
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 17, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

flake: Data race in coderd/x/chatd - TestArchiveChat

3 participants