aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/server/server.go20
1 files changed, 15 insertions, 5 deletions
diff --git a/internal/server/server.go b/internal/server/server.go
index f895be1..abd18cb 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -1,6 +1,7 @@
package server
import (
+ "bytes"
"context"
"embed"
"encoding/json"
@@ -71,7 +72,7 @@ func New(cfg *config.Config, store *storage.Storage, sched *monitor.Scheduler, l
Addr: fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port),
Handler: s.withMiddleware(mux),
ReadTimeout: 15 * time.Second,
- WriteTimeout: 15 * time.Second,
+ WriteTimeout: 30 * time.Second, // Increased for large page renders
IdleTimeout: 60 * time.Second,
}
@@ -347,11 +348,20 @@ func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) {
return false
})
- // Render template
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- if err := s.templates.ExecuteTemplate(w, "index.html", data); err != nil {
- // Log the error but don't try to send headers - they're already sent
+ // Render template to buffer first to prevent broken pipe errors
+ // This allows us to complete template execution even if client disconnects
+ var buf bytes.Buffer
+ if err := s.templates.ExecuteTemplate(&buf, "index.html", data); err != nil {
s.logger.Error("failed to render template", "error", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ // Write buffered response atomically
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ if _, err := w.Write(buf.Bytes()); err != nil {
+ // Client likely disconnected, just log it
+ s.logger.Debug("failed to write response", "error", err)
}
}