github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/databases/dbconn.go (about) 1 // Copyright 2023 IAC. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package dbconn 16 17 import ( 18 "database/sql" 19 "fmt" 20 "sync" 21 "time" 22 23 // "github.com/mdaxf/iac/com" 24 "github.com/mdaxf/iac/logger" 25 26 _ "github.com/denisenkom/go-mssqldb" 27 _ "github.com/go-sql-driver/mysql" 28 ) 29 30 // DB is the interface for database connection 31 var DB *sql.DB 32 var monitoring = false 33 var connectionerr error 34 35 // ConnectDB is the function to connect to database 36 // DatabaseType: mysql 37 // DatabaseConnection: user:password@tcp(localhost:3306)/mydb 38 // DatabaseName: iac 39 40 var ( 41 /* 42 mysql,sqlserver, goracle 43 */ 44 DatabaseType = "mysql" 45 46 /* 47 user:password@tcp(localhost:3306)/mydb 48 server=%s;port=%d;user id=%s;password=%s;database=%s 49 */ 50 //DatabaseConnection = "server=xxx;user id=xx;password=xxx;database=xxx" //sqlserver 51 DatabaseConnection = "user:iacf12345678@tcp(localhost:3306)/iac" 52 MaxIdleConns = 5 53 MaxOpenConns = 10 54 once sync.Once 55 err error 56 ) 57 58 // ConnectDB establishes a connection to the database. 59 // It returns an error if the connection fails. 60 61 func ConnectDB() error { 62 // Function execution logging 63 connectionerr = nil 64 iLog := logger.Log{ModuleName: logger.Framework, User: "System", ControllerName: "Database"} 65 startTime := time.Now() 66 defer func() { 67 elapsed := time.Since(startTime) 68 iLog.PerformanceWithDuration("database.ConnectDB", elapsed) 69 }() 70 71 // Recover from any panics and log the error 72 defer func() { 73 if err := recover(); err != nil { 74 iLog.Error(fmt.Sprintf("ConnectDB defer error: %s", err)) 75 connectionerr = err.(error) 76 return 77 // ctx.JSON(http.StatusBadRequest, gin.H{"error": err}) 78 } 79 }() 80 /* 81 dbconn := &com.DBConn{ 82 DBType: DatabaseType, 83 DBConnection: DatabaseConnection, 84 DBName: "", 85 MaxIdleConns: MaxIdleConns, 86 MaxOpenConns: MaxOpenConns, 87 } 88 89 mydbconn := &DBConn{ 90 DBType: DatabaseType, 91 DBConnection: DatabaseConnection, 92 DBName: "", 93 DB: nil, 94 MaxIdleConns: MaxIdleConns, 95 MaxOpenConns: MaxOpenConns, 96 } 97 98 err := mydbconn.Connect() 99 if err != nil { 100 iLog.Error(fmt.Sprintf("initialize Database (MySQL) error: %s", err.Error())) 101 return err 102 } 103 104 DB = mydbconn.DB 105 dbconn.DB = DB 106 iLog.Debug(fmt.Sprintf("Connect to database:%v", DB)) 107 com.IACDBConn = dbconn 108 109 return nil */ 110 111 // Log the database connection details 112 iLog.Info(fmt.Sprintf("Connect Database: %s %s", DatabaseType, DatabaseConnection)) 113 114 // Establish the database connection if it hasn't been done before 115 once.Do(func() { 116 DB, err = sql.Open(DatabaseType, DatabaseConnection) 117 if err != nil { 118 iLog.Error(fmt.Sprintf("Connect Database Error: %v", err)) 119 connectionerr = err 120 return 121 } 122 DB.SetMaxIdleConns(MaxIdleConns) 123 DB.SetMaxOpenConns(MaxOpenConns) 124 }) 125 126 if monitoring == false { 127 go func() { 128 monitorAndReconnectMySQL() 129 }() 130 } 131 132 return nil 133 134 } 135 136 // DBPing pings the database to check if it is still alive. 137 // It returns an error if the ping fails. 138 139 func DBPing() error { 140 iLog := logger.Log{ModuleName: logger.Framework, User: "System", ControllerName: "Database"} 141 startTime := time.Now() 142 defer func() { 143 elapsed := time.Since(startTime) 144 iLog.PerformanceWithDuration("database.DBPing", elapsed) 145 }() 146 147 defer func() { 148 if err := recover(); err != nil { 149 iLog.Error(fmt.Sprintf("DBPing defer error: %s", err)) 150 // ctx.JSON(http.StatusBadRequest, gin.H{"error": err}) 151 } 152 }() 153 154 return DB.Ping() 155 156 } 157 158 func monitorAndReconnectMySQL() { 159 // Function execution logging 160 iLog := logger.Log{ModuleName: logger.Framework, User: "System", ControllerName: "Database.monitorAndReconnectMySQL"} 161 startTime := time.Now() 162 defer func() { 163 elapsed := time.Since(startTime) 164 iLog.PerformanceWithDuration("database.monitorAndReconnectMySQL", elapsed) 165 }() 166 167 // Recover from any panics and log the error 168 defer func() { 169 if err := recover(); err != nil { 170 iLog.Error(fmt.Sprintf("monitorAndReconnectMySQL defer error: %s", err)) 171 // ctx.JSON(http.StatusBadRequest, gin.H{"error": err}) 172 } 173 }() 174 monitoring = true 175 for { 176 err := DB.Ping() 177 if err != nil { 178 iLog.Error(fmt.Sprintf("MySQL connection lost, reconnecting...")) 179 180 ConnectDB() 181 182 if connectionerr != nil { 183 iLog.Error(fmt.Sprintf("Failed to reconnect to MySQL:%v", connectionerr)) 184 time.Sleep(60 * time.Second) // Wait before retrying 185 continue 186 } else { 187 time.Sleep(5 * 60 * time.Second) 188 iLog.Debug(fmt.Sprintf("MySQL reconnected successfully")) 189 continue 190 } 191 } else { 192 time.Sleep(5 * 60 * time.Second) // Check connection every 60 seconds 193 continue 194 } 195 } 196 197 }