fix(sqlite,browser): resolve SQLite connection pool deadlock, disable stale SW cache, and update BRAIN.md
MindSift CI & Docker Release / Build, Test in Container & Push (push) Failing after 38s

This commit is contained in:
sandrodach committed 2026-10-24 21:27:51 +02:00
1 parent d6bc2976d9
commit 5c4e130862
8 files changed
+414 -231

No files matched your search

+38 -17
View File
@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"github.com/sandrodach/mindsift/internal/auth"
"github.com/sandrodach/mindsift/internal/domain"
@@ -15,22 +16,30 @@ import (
)
type Store struct {
db *sql.DB
db *sql.DB
initMu sync.Mutex
}
func NewStore(dbPath string) (*Store, error) {
dir := filepath.Dir(dbPath)
if err := os.MkdirAll(dir, 0755); err != nil {
return nil, fmt.Errorf("failed to create data directory %s: %w", dir, err)
if dbPath != ":memory:" && !strings.HasPrefix(dbPath, "file:") {
dir := filepath.Dir(dbPath)
if err := os.MkdirAll(dir, 0755); err != nil {
return nil, fmt.Errorf("failed to create data directory %s: %w", dir, err)
}
}
db, err := sql.Open("sqlite", dbPath)
dsn := dbPath
if !strings.Contains(dsn, "?") {
dsn += "?_pragma=busy_timeout(10000)&_pragma=journal_mode(WAL)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(1)"
}
db, err := sql.Open("sqlite", dsn)
if err != nil {
return nil, fmt.Errorf("failed to open sqlite db: %w", err)
}
db.SetMaxOpenConns(1) // SQLite WAL optimal writer serialization in single process
db.SetMaxIdleConns(1)
db.SetMaxOpenConns(8)
db.SetMaxIdleConns(4)
store := &Store{db: db}
if err := store.migrate(); err != nil {
@@ -266,6 +275,9 @@ func (s *Store) SeedStarterContent(user *domain.User) error {
// EnsureDefaultUser creates a default user if the database has 0 users so self-hosted users can jump right in
func (s *Store) EnsureDefaultUser() (*domain.User, error) {
s.initMu.Lock()
defer s.initMu.Unlock()
count, err := s.CountUsers()
if err != nil {
return nil, err
@@ -280,7 +292,7 @@ func (s *Store) EnsureDefaultUser() (*domain.User, error) {
}
user, err := s.CreateUser("admin@mindsift.local", hash, "Sandro")
if err != nil {
return nil, err
return s.GetFirstUser()
}
_ = s.SeedStarterContent(user)
return user, nil
@@ -872,7 +884,6 @@ func (s *Store) GetSpacesForUser(userID string) ([]domain.Space, error) {
if err != nil {
return nil, err
}
defer rows.Close()
spaces := make([]domain.Space, 0)
for rows.Next() {
@@ -880,11 +891,15 @@ func (s *Store) GetSpacesForUser(userID string) ([]domain.Space, error) {
var personalInt int
if err := rows.Scan(&sp.ID, &sp.Name, &sp.Icon, &sp.Description, &sp.InviteCode, &personalInt, &sp.OwnerID, &sp.CreatedAt); err == nil {
sp.IsPersonal = personalInt != 0
sp.Members, _ = s.GetSpaceMembers(sp.ID)
_ = s.db.QueryRow(`SELECT COUNT(*) FROM lists WHERE space_id = ?`, sp.ID).Scan(&sp.ListsCount)
spaces = append(spaces, sp)
}
}
_ = rows.Close()
for i := range spaces {
spaces[i].Members, _ = s.GetSpaceMembers(spaces[i].ID)
_ = s.db.QueryRow(`SELECT COUNT(*) FROM lists WHERE space_id = ?`, spaces[i].ID).Scan(&spaces[i].ListsCount)
}
return spaces, nil
}
@@ -929,16 +944,19 @@ func (s *Store) GetListsForSpace(spaceID string) ([]domain.SharedList, error) {
if err != nil {
return nil, err
}
defer rows.Close()
lists := make([]domain.SharedList, 0)
for rows.Next() {
var l domain.SharedList
if err := rows.Scan(&l.ID, &l.SpaceID, &l.Title, &l.Icon, &l.ListType, &l.UpdatedAt, &l.CreatedAt); err == nil {
l.Items, _ = s.GetListItems(l.ID)
lists = append(lists, l)
}
}
_ = rows.Close()
for i := range lists {
lists[i].Items, _ = s.GetListItems(lists[i].ID)
}
return lists, nil
}
@@ -954,16 +972,19 @@ func (s *Store) GetAllListsForUser(userID string) ([]domain.SharedList, error) {
if err != nil {
return nil, err
}
defer rows.Close()
lists := make([]domain.SharedList, 0)
for rows.Next() {
var l domain.SharedList
if err := rows.Scan(&l.ID, &l.SpaceID, &l.Title, &l.Icon, &l.ListType, &l.UpdatedAt, &l.CreatedAt); err == nil {
l.Items, _ = s.GetListItems(l.ID)
lists = append(lists, l)
}
}
_ = rows.Close()
for i := range lists {
lists[i].Items, _ = s.GetListItems(lists[i].ID)
}
return lists, nil
}
@@ -1183,12 +1204,12 @@ func (s *Store) SearchAll(userID, query string) ([]domain.Thought, []domain.Docu
)
thoughts := make([]domain.Thought, 0)
if err == nil {
defer tRows.Close()
for tRows.Next() {
if t, err := scanThought(tRows); err == nil {
thoughts = append(thoughts, *t)
}
}
_ = tRows.Close()
}
dRows, err := s.db.Query(
@@ -1198,12 +1219,12 @@ func (s *Store) SearchAll(userID, query string) ([]domain.Thought, []domain.Docu
)
docs := make([]domain.Document, 0)
if err == nil {
defer dRows.Close()
for dRows.Next() {
if d, err := scanDocument(dRows); err == nil {
docs = append(docs, *d)
}
}
_ = dRows.Close()
}
return thoughts, docs, nil