I met some weird situation with such simple code:
func InitDatabase(dataSourceName string) {
var err error
DBCon, err = sql.Open("mysql", dataSourceName)
if err != nil {
log.Panic(err)
}
log.Println("Ping...")
if err = DBCon.Ping(); err != nil { // <- it hangs here
log.Println(":(")
}
log.Println(":)")
}
I debugged and found, that it locks goroutine in this line (fd_poll_runtime.go, line #85), looks like it even doesn't connect:
res := runtime_pollWait(pd.runtimeCtx, mode)
It can wait here for ages, my mac becomes very hot.
I made a small change:
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err = DBCon.PingContext(ctx); err != nil {
log.Println(":(")
}
log.Println(":)")
And it still hangs and timeout doesn't work.
Problem is, that it worked yesterday (and, funny, it works on my friend's machine, same params) and now it doesn't even after reboot and after reinstalling mysql (which works perfectly in terminal/goland/mysqlworkbench).
Go version 1.9, mysql driver: "github.com/go-sql-driver/mysql", mysql version: 5.7.20 Homebrew, macos version: High Sierra 10.13.1, I host mysql on localhost, port 3306.
UPDATE
It finally worked. I copied init code to the clean project and it worked there. I started to comment out code, to find where is the problem. I found that I have this code in the imported package. Even if code from this package executes after database ping, but init code executes before and somehow it blocks db.Ping()
:
func init() {
for i := 1; i <= maxWorkers; i++ {
go func(i int) {
for {
select {
case j, ok := <-jobs:
if ok {
j.invoke()
} else {
// loop
}
default:
// loop
}
}
}(i)
}
}
I rewrote method name and executed it after database ping and everything worked.
I don't know why it happened, but if you have the answer, feel free to post it here.