Skip to content

Commit 012a9e7

Browse files
authored
fix: Avoid deadlock in AgentReportStats Close during agent Close (coder#5415)
Since AgentReportStats takes a stats function which was doing mutex locking on agent shutdown, it was possible for there to be a deadlock depending on how the AgentReportsStats Close function is implemented. This mostly seems to happen on Windows test runners as it's pretty hard to hit this edge case. The bug currently only exists in the test implementation of AgentReportStats, however, this was refactored to be more robust in case of future changes.
1 parent 8e702d8 commit 012a9e7

File tree

1 file changed

+19
-22
lines changed

1 file changed

+19
-22
lines changed

agent/agent.go

+19-22
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,25 @@ func (a *agent) run(ctx context.Context) error {
226226
_ = network.Close()
227227
return xerrors.New("agent is closed")
228228
}
229+
230+
// Report statistics from the created network.
231+
cl, err := a.client.AgentReportStats(ctx, a.logger, func() *codersdk.AgentStats {
232+
stats := network.ExtractTrafficStats()
233+
return convertAgentStats(stats)
234+
})
235+
if err != nil {
236+
a.logger.Error(ctx, "report stats", slog.Error(err))
237+
} else {
238+
if err = a.trackConnGoroutine(func() {
239+
// This is OK because the agent never re-creates the tailnet
240+
// and the only shutdown indicator is agent.Close().
241+
<-a.closed
242+
_ = cl.Close()
243+
}); err != nil {
244+
a.logger.Debug(ctx, "report stats goroutine", slog.Error(err))
245+
_ = cl.Close()
246+
}
247+
}
229248
} else {
230249
// Update the DERP map!
231250
network.SetDERPMap(metadata.DERPMap)
@@ -561,28 +580,6 @@ func (a *agent) init(ctx context.Context) {
561580
}
562581

563582
go a.runLoop(ctx)
564-
cl, err := a.client.AgentReportStats(ctx, a.logger, func() *codersdk.AgentStats {
565-
stats := map[netlogtype.Connection]netlogtype.Counts{}
566-
a.closeMutex.Lock()
567-
if a.network != nil {
568-
stats = a.network.ExtractTrafficStats()
569-
}
570-
a.closeMutex.Unlock()
571-
return convertAgentStats(stats)
572-
})
573-
if err != nil {
574-
a.logger.Error(ctx, "report stats", slog.Error(err))
575-
return
576-
}
577-
578-
if err = a.trackConnGoroutine(func() {
579-
<-a.closed
580-
_ = cl.Close()
581-
}); err != nil {
582-
a.logger.Error(ctx, "report stats goroutine", slog.Error(err))
583-
_ = cl.Close()
584-
return
585-
}
586583
}
587584

588585
func convertAgentStats(counts map[netlogtype.Connection]netlogtype.Counts) *codersdk.AgentStats {

0 commit comments

Comments
 (0)