From c8eb8de65140a3c7f011bb24b189ea5c8ff77f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Markovi=C4=87?= Date: Fri, 12 Jun 2026 21:56:17 +0200 Subject: [PATCH] =?UTF-8?q?fix(backup):=20pozadinske=20gorutine=20koriste?= =?UTF-8?q?=20sve=C5=BEu=20konekciju=20posle=20obnove=20Auto-backup=20i=20?= =?UTF-8?q?=C4=8Di=C5=A1=C4=87enje=20sesija/poku=C5=A1aja=20su=20koristili?= =?UTF-8?q?=20originalni=20db=20handle=20iz=20main.go,=20koji=20posle=20ob?= =?UTF-8?q?nove=20backupa=20(VratiBackup)=20ostaje=20zatvoren=20=E2=80=94?= =?UTF-8?q?=20gorutine=20bi=20prestale=20da=20rade=20do=20restarta.=20Sada?= =?UTF-8?q?=20rade=20preko=20novog=20helpera=20h.SaBazom,=20koji=20pod=20d?= =?UTF-8?q?eljenim=20zaklju=C4=8Davanjem=20prosle=C4=91uje=20trenutnu=20h.?= =?UTF-8?q?DB,=20pa=20vide=20zamenjenu=20konekciju.=20Gorutine=20su=20prem?= =?UTF-8?q?e=C5=A1tene=20da=20startuju=20posle=20kreiranja=20h.=20time.Sle?= =?UTF-8?q?ep=20je=20van=20zaklju=C4=8Davanja=20da=20ne=20odla=C5=BEe=20ob?= =?UTF-8?q?novu.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/ntech/main.go | 52 +++++++++++++++++++++---------------- internal/handler/handler.go | 11 ++++++++ 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/cmd/ntech/main.go b/cmd/ntech/main.go index 874ca5f..c878b5f 100644 --- a/cmd/ntech/main.go +++ b/cmd/ntech/main.go @@ -109,28 +109,6 @@ func main() { napraviBackup(db, putanjaBaze) - // periodični automatski backup — interval se čita iz podešavanja u svakom ciklusu, - // tako da izmena u podešavanjima stupa na snagu bez restarta (od sledećeg ciklusa) - go func() { - for { - sati := procitajIntPodesavanje(db, "backup_interval_sati", 24) - time.Sleep(time.Duration(sati) * time.Hour) - napraviBackup(db, putanjaBaze) - } - }() - - // periodično brisanje isteklih sesija i starih pokušaja prijave - go func() { - ticker := time.NewTicker(time.Hour) - defer ticker.Stop() - sesijeRepo := sqlite.NoviSesijeRepo(db) - pokusajiRepo := sqlite.NoviPokusajiPrijaveRepo(db) - for range ticker.C { - _ = sesijeRepo.ObrisiIstekle(context.Background()) - _ = pokusajiRepo.ObrisiStare(context.Background(), time.Now().Add(-24*time.Hour)) - } - }() - os.MkdirAll("web/static/uploads", 0755) h := handler.Novi(db, totpKljuc) @@ -151,6 +129,36 @@ func main() { log.Printf("Keš šablona kreiran: %d šablona", len(kes)) } + // Pozadinske gorutine se pokreću posle kreiranja h i rade preko h.SaBazom, + // pa uvek koriste TRENUTNU konekciju baze (posle obnove backupa h.DB se menja). + + // periodični automatski backup — interval se čita iz podešavanja u svakom + // ciklusu, pa izmena stupa na snagu bez restarta (od sledećeg ciklusa) + go func() { + for { + sati := 24 + h.SaBazom(func(db *sql.DB) { + sati = procitajIntPodesavanje(db, "backup_interval_sati", 24) + }) + time.Sleep(time.Duration(sati) * time.Hour) + h.SaBazom(func(db *sql.DB) { + napraviBackup(db, putanjaBaze) + }) + } + }() + + // periodično brisanje isteklih sesija i starih pokušaja prijave + go func() { + ticker := time.NewTicker(time.Hour) + defer ticker.Stop() + for range ticker.C { + h.SaBazom(func(db *sql.DB) { + _ = sqlite.NoviSesijeRepo(db).ObrisiIstekle(context.Background()) + _ = sqlite.NoviPokusajiPrijaveRepo(db).ObrisiStare(context.Background(), time.Now().Add(-24*time.Hour)) + }) + } + }() + r := chi.NewRouter() r.Use(ntechmw.BezbednostHeaders()) r.Use(ntechmw.CsrfMiddleware) diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 85e7d4f..53a2705 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -57,6 +57,17 @@ func (h *Handler) ZakljucajCitanje(next http.Handler) http.Handler { }) } +// SaBazom izvršava fn sa TRENUTNOM konekcijom baze, pod deljenim zaključavanjem. +// Namenjeno pozadinskim gorutinama (auto-backup, čišćenje): posle obnove backupa +// h.DB se menja, pa gorutine moraju da čitaju aktuelni handle, a ne zatvoreni. +// Zaključavanje se drži samo za vreme fn — ne pozivaj iz njega operacije koje +// dugo blokiraju (npr. time.Sleep), da ne bi nepotrebno odlagao obnovu. +func (h *Handler) SaBazom(fn func(*sql.DB)) { + h.mu.RLock() + defer h.mu.RUnlock() + fn(h.DB) +} + // Novi kreira novi Handler sa datom bazom. // totpKljuc je 32-bajtni ključ za šifrovanje TOTP tajni u mirovanju. func Novi(baza *sql.DB, totpKljuc []byte) *Handler {