99 "log"
1010 "net/http"
1111 "os"
12+ "sync"
1213 "time"
1314
1415 "github.com/skip2/go-qrcode"
@@ -111,6 +112,16 @@ func TimeUntilExpiration(expiration *time.Time) string {
111112 return ""
112113}
113114
115+ var (
116+ lastStatusCode int
117+ lastStatus string
118+ lastDBStatus string
119+ lastModTime time.Time
120+ lastSize int64
121+ cacheMu sync.RWMutex
122+ cacheInit bool
123+ )
124+
114125// Application health check
115126func HealthCheck (w http.ResponseWriter , r * http.Request ) {
116127 statusCode := http .StatusOK
@@ -123,34 +134,63 @@ func HealthCheck(w http.ResponseWriter, r *http.Request) {
123134 dbStatus = "missing_file"
124135 } else {
125136 // Check DB file exists
126- if info , err := os .Stat (db .DBPath ); os .IsNotExist (err ) {
137+ info , err := os .Stat (db .DBPath )
138+ if os .IsNotExist (err ) {
127139 statusCode = http .StatusInternalServerError
128140 status = "error"
129141 dbStatus = "missing_file"
130- } else if info .Size () < 100 {
131- // File too small to be valid sqlite
142+ } else if err != nil {
132143 statusCode = http .StatusInternalServerError
133144 status = "error"
134- dbStatus = "corrupted "
145+ dbStatus = "unreachable "
135146 } else {
136- // Open a new connection to check integrity
137- tmpDB , err := gorm .Open (sqlite .Open (db .DBPath ), & gorm.Config {})
138- if err != nil {
139- statusCode = http .StatusInternalServerError
140- status = "error"
141- dbStatus = "corrupted"
142- } else {
143- var result int
144- if err := tmpDB .Raw ("SELECT 1" ).Scan (& result ).Error ; err != nil || result != 1 {
147+ // Only re-check if cache initialized and file unchanged
148+ cacheMu .RLock ()
149+ cached := cacheInit && info .ModTime ().Equal (lastModTime ) && info .Size () == lastSize
150+ if cached {
151+ statusCode = lastStatusCode
152+ status = lastStatus
153+ dbStatus = lastDBStatus
154+ }
155+ cacheMu .RUnlock ()
156+
157+ if ! cached {
158+ if info .Size () < 100 {
159+ // File too small to be valid sqlite
145160 statusCode = http .StatusInternalServerError
146161 status = "error"
147- dbStatus = "unreachable"
162+ dbStatus = "corrupted"
163+ } else {
164+ // Open a new connection to check integrity
165+ tmpDB , err := gorm .Open (sqlite .Open (db .DBPath ), & gorm.Config {})
166+ if err != nil {
167+ statusCode = http .StatusInternalServerError
168+ status = "error"
169+ dbStatus = "corrupted"
170+ } else {
171+ var result int
172+ if err := tmpDB .Raw ("SELECT 1" ).Scan (& result ).Error ; err != nil || result != 1 {
173+ statusCode = http .StatusInternalServerError
174+ status = "error"
175+ dbStatus = "unreachable"
176+ }
177+
178+ // Close underlying connection pool to avoid memory leaks
179+ if sqlDB , err := tmpDB .DB (); err == nil {
180+ sqlDB .Close ()
181+ }
182+ }
148183 }
149184
150- // Close underlying connection pool to avoid memory leaks
151- if sqlDB , err := tmpDB .DB (); err == nil {
152- sqlDB .Close ()
153- }
185+ // Update cache after full check
186+ cacheMu .Lock ()
187+ lastStatusCode = statusCode
188+ lastStatus = status
189+ lastDBStatus = dbStatus
190+ lastModTime = info .ModTime ()
191+ lastSize = info .Size ()
192+ cacheInit = true
193+ cacheMu .Unlock ()
154194 }
155195 }
156196 }
0 commit comments