-
Notifications
You must be signed in to change notification settings - Fork 27
Open
Description
The following goroutine is leaky by design and can be fixed by simply making the channel size 1.
Line 363 in c1fd63b
| func (w *World) Run(syms *SymbolTable) error { |
func (w *World) Run(syms *SymbolTable) error {
done := make(chan error) // Unbuffered channel makes the goroutine leaky
ctx, cancel := context.WithTimeout(context.Background(), w.runLimits.maxDuration)
defer cancel()
go func() {
for i := 0; i < w.runLimits.maxIterations; i++ {
select {
case <-ctx.Done():
return
default:
var newFacts FactSet
for _, r := range w.rules {
select {
case <-ctx.Done():
return
default:
if err := r.Apply(w.facts, &newFacts, syms); err != nil {
done <- err
return
}
}
}
prevCount := len(*w.facts)
w.facts.InsertAll([]Fact(newFacts))
newCount := len(*w.facts)
if newCount >= w.runLimits.maxFacts {
done <- ErrWorldRunLimitMaxFacts // Can block and run goroutine forever if context.Done() returns first
return
}
// last iteration did not generate any new facts, so we can stop here
if newCount == prevCount {
done <- nil // Can block and run goroutine forever if context.Done() returns first
return
}
}
}
done <- ErrWorldRunLimitMaxIterations
}()
select {
case <-ctx.Done():
return ErrWorldRunLimitTimeout
case err := <-done:
return err
}
}The simple fix is to set the channel size to 1:
done := make(chan error, 1) Playground can demonstrate the issue: https://goplay.tools/snippet/5j4Bkegd1dj
(change the channel size from unbuffered to 1 to see the result)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels