1

sorry if the Title is misleadling I didn't know how to ask it properly. I'll explain my situation as much as I can.

I have a go-gin web server running. Lately it get's stuck. Not responding to requests anymore and I don't have a timeout logic(which might be my problem) therefore I'm waiting the request response forever. The machine is windows, I was checking resource monitor and task manager in case of leak, which was not the case. Once the web server got frozen(not responding to requests anymore) I used netstat command to see the open connections and found out there was tons of :3306 in state of TIME_WAIT like 80ish or something. I think this is causing my web server to not respond new request's anymore. When I checked console output I saw the requests that can come in was actually getting response in 2-40ish ms. which is normal.

TL;DR

I think my database connection is not correct, it's not getting closed properly and causing to run out of ports.

I'll share my code below, can someone point me which part might be causing this issue?

//main.go
func createDBPool(connectionString string, maxConnections int) (*sql.DB, error) {
    db, err := sql.Open("mysql", connectionString)
    if err != nil {
        return nil, err
    }
    db.SetMaxOpenConns(maxConnections) // Set the maximum number of open connections
    return db, nil
}

func main() {
// Initialize database connection => field GlobalDBPool *sql.DB
//config.GlobalDbCon => "dbusername:dbuserpassword@tcp(dbip:dbport)/databasename
config.GlobalDBPool, err = createDBPool(config.GlobalDbCon, 30)
    if err != nil {
        sC.Logger.Error("Couldn't initialize database connection to global database.", "Error", err)
        os.Exit(1)
    }
    defer config.GlobalDBPool.Close()
//..Some other initialization codes are here
//This is how I distribute my config which contains database connection and other stuff
RSSServices := sC.RSSServices{ServerConfig: config}
userService := sC.UserService{ServerConfig: config}
subService := sC.SubscriptionService{ServerConfig: config}

//Again some code here and then routes come in place
r.GET("/some-endpoint", userService.SomeEndPointGET())
r.POST("/another-endpoint", subService.AnotherEndpointPOST())
err = r.Run(":80")
if err != nil {
        sC.Logger.Error("Server couldn't be initialized.", "Error", err)
        os.Exit(3)
    }
}

This is how I use the connection. I've checked all my functions and they are all same/similar

//SubscriptionService.go
type UserService struct {
    ServerConfig *models.Config
}

func (us *UserService) AnotherEndpointPOST() func(c *gin.Context) {
    sqlStatement := `PLACEHOLDER-SQL-STATEMENT-FOR-PRIVACY`

    err := us.ServerConfig.GlobalDBPool.QueryRow(sqlStatement, "param1").Scan(&var1, &var2, &var3)
    if err != nil {
        c.JSON(400, gin.H{"code": "some-error-code-string"})
            return
    }

    outputVar := fmt.Sprintf("\\\\%s\\%s\\%s", var1, var2, var3)

    c.JSON(200, gin.H{"code": "outputVar"})
}

I had to replace my sql and some variables. But in general this is how I use the database connection in every endpoint. I don't manually close or dispose anything which I think is wrong. Can someone point me if this approach is correct or should I close the connections? I use the "database/sql" library in my code.

7
  • what is the dbConn in dbConn.QueryRow? How do you get it? Commented Oct 14 at 15:43
  • How many is that tons of connection to mysql? Your code creates a connection pool, so there is got to be more than one connections to mysql for sure.
    – Shadow
    Commented Oct 14 at 16:02
  • @Shadow they seem to be saying the connections are to their webserver, not mysql. not clear mysql is at all involved in this.
    – ysth
    Commented Oct 14 at 16:13
  • 2
    We <ould need a more complete chunk of code to understand what is going on. For example: if I read your current snippet, the main() function calls createDBPool() and exists right away, the other things your mention (named xxxService) are initialized outside of the main function,and no code shows how the fields in config are used in your code (do you use config.GlobalDBPool ? or config.GlobalDBCon ? or something else ? ...)
    – LeGEC
    Commented Oct 14 at 16:37
  • 1
    "don't close them with rows.Close()" - the usage example is probably a good place to start, there is also a tutorial and quite a few questions here. If close is not called (and you don't process the full result set) then a connection is leaked.
    – Brits
    Commented Oct 14 at 21:36

0

Browse other questions tagged or ask your own question.