Reputation: 96767
Been trying to use gonnel for some tunnels. Tried to open 2 tunnels, and then when they got closed, I noticed that the log package is saying that is trying to close the same tunnel twice. From looking at the code, it seems that (one of) the problems is this:
I thought I would take advantage of staticcheck, golangci-lint or even go vet to have it highlight this problem, so that I can be more confident on a fix. However, when I run the tools, I get this output:
go vet:
staticcheck:
Also tried running go vet with -loopclosure, but I still don't get any output. Shouldn't one of the tools say that the go func needs the iterator variable passed as param? If it helps, I'm running go 1.14.3 darwin/amd64, and also tried importing the code in goland, but I didn't get an inspection warning for that piece of code. I am getting a feeling that I might be doing something wrong, could you spot what it is?
Thanks!
Upvotes: 3
Views: 1505
Reputation: 4204
Yes, correct. This problem is very common among Gophers (What happens with closures running as goroutines?)!
Go vet's issues:
So, it seems you don't see an output with go vet because the goroutine in within an if
block. Could you try doing it without the if
block? I think your issue is more relevant Issue 21412
Similarly for golangci/govet:
Quoting from the golangci/govet/rangeloop.go
's code:
This file contains the code to check range loop variables bound inside function
literals that are deferred or launched in new goroutines. We only check
instances where the defer or go statement is the last statement in the loop
body, as otherwise, we would need whole-program analysis.
Also, my suggestion would be to check if tunnels are open and then only close it. It might happen that you duplicate entries, so then again there's a possibility of some issue. And do fix the closure running as a goroutine error, first.
So, here's an example where the if
block is a differentiator on how go vet
works.
if
block, go vet
returns nothingpackage main
import (
"fmt"
"sync"
)
func main() {
fruits := []string{"orange", "apple"}
var wg sync.WaitGroup
for _, fruit := range fruits {
if true {
wg.Add(1)
go func() {
fmt.Println(fruit)
wg.Done()
}()
}
}
wg.Wait()
}
if
block, go vet
returns loop variable fruit captured by func literal
package main
import (
"fmt"
"sync"
)
func main() {
fruits := []string{"orange", "apple"}
var wg sync.WaitGroup
for _, fruit := range fruits {
wg.Add(1)
go func() {
fmt.Println(fruit)
wg.Done()
}()
}
wg.Wait()
}
Upvotes: 2