From a30861984c4b5dbd19206e2d9e3cdda36b3f7405 Mon Sep 17 00:00:00 2001 From: Mukhtar Akere Date: Tue, 11 Mar 2025 18:08:03 +0100 Subject: [PATCH] Fix saveTofile; Add a global panic, Add a recoverer for everything functions --- cmd/decypharr/main.go | 57 ++++++++++++++++++++++++++----------------- main.go | 7 ++++++ pkg/qbit/storage.go | 4 +-- 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/cmd/decypharr/main.go b/cmd/decypharr/main.go index b203bd1..9aaaea0 100644 --- a/cmd/decypharr/main.go +++ b/cmd/decypharr/main.go @@ -2,6 +2,7 @@ package decypharr import ( "context" + "fmt" "github.com/sirrobot01/debrid-blackhole/internal/config" "github.com/sirrobot01/debrid-blackhole/internal/logger" "github.com/sirrobot01/debrid-blackhole/pkg/proxy" @@ -11,7 +12,7 @@ import ( "github.com/sirrobot01/debrid-blackhole/pkg/version" "github.com/sirrobot01/debrid-blackhole/pkg/web" "github.com/sirrobot01/debrid-blackhole/pkg/worker" - "log" + "runtime/debug" "sync" ) @@ -36,41 +37,51 @@ func Start(ctx context.Context) error { srv.Mount("/", webRoutes) srv.Mount("/api/v2", qbitRoutes) - if cfg.Proxy.Enabled { + safeGo := func(f func() error) { wg.Add(1) go func() { defer wg.Done() - if err := proxy.NewProxy().Start(ctx); err != nil { + defer func() { + if r := recover(); r != nil { + stack := debug.Stack() + _log.Error(). + Interface("panic", r). + Str("stack", string(stack)). + Msg("Recovered from panic in goroutine") + + // Send error to channel so the main goroutine is aware + errChan <- fmt.Errorf("panic: %v", r) + } + }() + + if err := f(); err != nil { errChan <- err } }() } - wg.Add(1) - go func() { - defer wg.Done() - if err := srv.Start(ctx); err != nil { - errChan <- err - } + if cfg.Proxy.Enabled { + safeGo(func() error { + return proxy.NewProxy().Start(ctx) + }) + } - }() + safeGo(func() error { + return srv.Start(ctx) + }) - wg.Add(1) - go func() { - defer wg.Done() - if err := worker.Start(ctx); err != nil { - errChan <- err - } - }() + safeGo(func() error { + return worker.Start(ctx) + }) if cfg.Repair.Enabled { - wg.Add(1) - go func() { - defer wg.Done() - if err := svc.Repair.Start(ctx); err != nil { - log.Printf("Error during repair: %v", err) + safeGo(func() error { + err := svc.Repair.Start(ctx) + if err != nil { + _log.Error().Err(err).Msg("Error during repair") } - }() + return nil // Not propagating repair errors to terminate the app + }) } go func() { diff --git a/main.go b/main.go index 0c7ed3b..9e162dd 100644 --- a/main.go +++ b/main.go @@ -6,9 +6,16 @@ import ( "github.com/sirrobot01/debrid-blackhole/cmd/decypharr" "github.com/sirrobot01/debrid-blackhole/internal/config" "log" + "runtime/debug" ) func main() { + defer func() { + if r := recover(); r != nil { + log.Printf("FATAL: Recovered from panic in main: %v\n", r) + debug.PrintStack() + } + }() var configPath string flag.StringVar(&configPath, "config", "/data", "path to the data folder") flag.Parse() diff --git a/pkg/qbit/storage.go b/pkg/qbit/storage.go index ed6b2f2..844bf96 100644 --- a/pkg/qbit/storage.go +++ b/pkg/qbit/storage.go @@ -219,14 +219,14 @@ func (ts *TorrentStorage) DeleteMultiple(hashes []string) { } func (ts *TorrentStorage) Save() error { - ts.mu.RLock() - defer ts.mu.RUnlock() return ts.saveToFile() } // saveToFile is a helper function to write the current state to the JSON file func (ts *TorrentStorage) saveToFile() error { + ts.mu.RLock() data, err := json.MarshalIndent(ts.torrents, "", " ") + ts.mu.RUnlock() if err != nil { return err }