diff --git a/PROJECTS/beginner/canary-token-generator/backend/internal/core/database.go b/PROJECTS/beginner/canary-token-generator/backend/internal/core/database.go index d4849ce3..00d3642b 100644 --- a/PROJECTS/beginner/canary-token-generator/backend/internal/core/database.go +++ b/PROJECTS/beginner/canary-token-generator/backend/internal/core/database.go @@ -5,9 +5,11 @@ package core import ( "context" + crand "crypto/rand" "database/sql" "fmt" - "math/rand/v2" + "log/slog" + "math/big" "time" _ "github.com/jackc/pgx/v5/stdlib" @@ -41,9 +43,15 @@ func NewDatabase( pingCtx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - if err := db.PingContext(pingCtx); err != nil { - _ = db.Close() //nolint:errcheck // cleanup on connection failure - return nil, fmt.Errorf("ping database: %w", err) + if pingErr := db.PingContext(pingCtx); pingErr != nil { + if closeErr := db.Close(); closeErr != nil { + return nil, fmt.Errorf( + "ping database: %w (close also failed: %w)", + pingErr, + closeErr, + ) + } + return nil, fmt.Errorf("ping database: %w", pingErr) } return &Database{DB: db}, nil @@ -91,7 +99,12 @@ func InTx(ctx context.Context, db *sqlx.DB, fn func(tx *sqlx.Tx) error) error { defer func() { if p := recover(); p != nil { - _ = tx.Rollback() //nolint:errcheck // best-effort rollback on panic + if rbErr := tx.Rollback(); rbErr != nil { + slog.Error( + "rollback failed during panic recovery", + "error", rbErr, + ) + } panic(p) } }() @@ -123,7 +136,12 @@ func InTxWithOptions( defer func() { if p := recover(); p != nil { - _ = tx.Rollback() //nolint:errcheck // best-effort rollback on panic + if rbErr := tx.Rollback(); rbErr != nil { + slog.Error( + "rollback failed during panic recovery", + "error", rbErr, + ) + } panic(p) } }() @@ -143,7 +161,13 @@ func InTxWithOptions( } func jitteredDuration(base time.Duration) time.Duration { - //nolint:gosec // G404: non-security-sensitive jitter for connection pool - jitter := time.Duration(rand.Int64N(int64(base / 7))) - return base + jitter + maxJitter := int64(base / 7) + if maxJitter <= 0 { + return base + } + jitter, err := crand.Int(crand.Reader, big.NewInt(maxJitter)) + if err != nil { + return base + } + return base + time.Duration(jitter.Int64()) } diff --git a/PROJECTS/beginner/canary-token-generator/backend/internal/health/handler.go b/PROJECTS/beginner/canary-token-generator/backend/internal/health/handler.go index e77793c6..c95c2b8f 100644 --- a/PROJECTS/beginner/canary-token-generator/backend/internal/health/handler.go +++ b/PROJECTS/beginner/canary-token-generator/backend/internal/health/handler.go @@ -6,6 +6,7 @@ package health import ( "context" "encoding/json" + "log/slog" "net/http" "sync" "sync/atomic" @@ -174,8 +175,9 @@ func (h *Handler) writeStatus(w http.ResponseWriter, status int, data any) { w.Header().Set("Content-Type", "application/json") w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") w.WriteHeader(status) - //nolint:errcheck // best-effort response - _ = json.NewEncoder(w).Encode(data) + if err := json.NewEncoder(w).Encode(data); err != nil { + slog.Error("failed to encode health response", "error", err) + } } type StatusResponse struct { diff --git a/PROJECTS/beginner/canary-token-generator/backend/internal/middleware/ratelimit.go b/PROJECTS/beginner/canary-token-generator/backend/internal/middleware/ratelimit.go index c57f38e1..c52b0b0e 100644 --- a/PROJECTS/beginner/canary-token-generator/backend/internal/middleware/ratelimit.go +++ b/PROJECTS/beginner/canary-token-generator/backend/internal/middleware/ratelimit.go @@ -154,8 +154,9 @@ func writeRateLimitExceeded(w http.ResponseWriter, res *redis_rate.Result) { }, } - //nolint:errcheck // best-effort response write - _ = json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode rate-limit response", "error", err) + } } type limiterEntry struct {