Skip to content

Commit 9f1ddeb

Browse files
committed
Fix SQLite locked errors and cleanup crash with busy_timeout and retry logic
1 parent 7c37ef5 commit 9f1ddeb

File tree

2 files changed

+58
-12
lines changed

2 files changed

+58
-12
lines changed

src/wigo/global.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,18 +211,44 @@ Options:
211211
log.Fatalf("Fail to create table in sqlite database : %s\n", err)
212212
}
213213

214+
// Configure SQLite busy timeout to handle concurrent access
215+
_, err = LocalWigo.sqlLiteConn.Exec("PRAGMA busy_timeout = 5000")
216+
if err != nil {
217+
log.Fatalf("Fail to configure sqlite busy_timeout : %s\n", err)
218+
}
219+
214220
// Launch cleaning routing
215221
go func() {
216222
for {
217223
ts := time.Now().Unix() - 86400*30
218224
sqlStmt := `DELETE FROM logs WHERE date < ?;`
219225

220-
LocalWigo.sqlLiteLock.Lock()
221-
_, err = LocalWigo.sqlLiteConn.Exec(sqlStmt, ts)
222-
if err != nil {
223-
log.Fatalf("Fail to clean logs in database : %s\n", err)
226+
maxRetries := 3
227+
backoffDelays := []time.Duration{50 * time.Millisecond, 100 * time.Millisecond, 200 * time.Millisecond}
228+
229+
var err error
230+
for attempt := 0; attempt < maxRetries; attempt++ {
231+
LocalWigo.sqlLiteLock.Lock()
232+
_, err = LocalWigo.sqlLiteConn.Exec(sqlStmt, ts)
233+
LocalWigo.sqlLiteLock.Unlock()
234+
235+
if err == nil {
236+
break
237+
}
238+
239+
// Check if error is SQLITE_BUSY or database locked
240+
errStr := err.Error()
241+
isBusyError := strings.Contains(errStr, "SQLITE_BUSY")
242+
243+
if !isBusyError || attempt == maxRetries-1 {
244+
// Not a busy error or last attempt, log and break
245+
log.Printf("Fail to clean logs in database : %s\n", err)
246+
break
247+
}
248+
249+
// Wait before retry
250+
time.Sleep(backoffDelays[attempt])
224251
}
225-
LocalWigo.sqlLiteLock.Unlock()
226252

227253
time.Sleep(time.Hour)
228254
}

src/wigo/log.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package wigo
33
import (
44
"log"
55
"os"
6+
"strings"
67
"time"
78
)
89

@@ -44,15 +45,34 @@ func (this *Log) SetGroup(group string) {
4445

4546
// Persist on disk
4647
func (this *Log) Persist() {
47-
LocalWigo.sqlLiteLock.Lock()
48-
defer LocalWigo.sqlLiteLock.Unlock()
49-
5048
sqlStmt := `INSERT INTO logs(date,level,grp,host,probe,message) VALUES(?,?,?,?,?,?);`
51-
_, err := LocalWigo.sqlLiteConn.Exec(sqlStmt, this.Timestamp, this.Level, this.Group, this.Host, this.Probe, this.Message)
52-
if err != nil {
53-
log.Printf("Fail to insert log in sqlLite : %s", err)
49+
50+
maxRetries := 3
51+
backoffDelays := []time.Duration{50 * time.Millisecond, 100 * time.Millisecond, 200 * time.Millisecond}
52+
53+
var err error
54+
for attempt := 0; attempt < maxRetries; attempt++ {
55+
LocalWigo.sqlLiteLock.Lock()
56+
_, err = LocalWigo.sqlLiteConn.Exec(sqlStmt, this.Timestamp, this.Level, this.Group, this.Host, this.Probe, this.Message)
57+
LocalWigo.sqlLiteLock.Unlock()
58+
59+
if err == nil {
60+
return
61+
}
62+
63+
// Check if error is SQLITE_BUSY or database locked
64+
errStr := err.Error()
65+
isBusyError := strings.Contains(errStr, "SQLITE_BUSY")
66+
67+
if !isBusyError || attempt == maxRetries-1 {
68+
// Not a busy error or last attempt, log and return
69+
log.Printf("Fail to insert log in sqlLite : %s", err)
70+
return
71+
}
72+
73+
// Wait before retry
74+
time.Sleep(backoffDelays[attempt])
5475
}
55-
return
5676
}
5777

5878
// Log levels

0 commit comments

Comments
 (0)