diff --git a/go/cmd/pusherservice/main.go b/go/cmd/pusherservice/main.go index 816bb9d..5d160bd 100644 --- a/go/cmd/pusherservice/main.go +++ b/go/cmd/pusherservice/main.go @@ -52,15 +52,15 @@ func main() { // Pusher core bridge := pusher.NewRedisBridge(pusherRedis, podID) - authorizer := pusher.NewAuthorizer(networkSvc) - hub := pusher.NewHub(bridge, authorizer) - bridge.SetHub(hub) - server := pusher.NewServer(hub, bridge, authSvc) - // Context for graceful shutdown ctx, cancel := context.WithCancel(context.Background()) defer cancel() + authorizer := pusher.NewAuthorizer(networkSvc) + hub := pusher.NewHub(bridge, authorizer) + bridge.SetHub(hub) + server := pusher.NewServer(ctx, hub, bridge, authSvc) + // Start hub event loop go hub.Run(ctx) diff --git a/go/internal/pusher/server.go b/go/internal/pusher/server.go index 37b997f..1b4dd9d 100644 --- a/go/internal/pusher/server.go +++ b/go/internal/pusher/server.go @@ -15,14 +15,17 @@ import ( type Server struct { pbpusher.UnimplementedPusherServiceServer + ctx context.Context // server-scoped context for graceful shutdown hub *Hub bridge *RedisBridge authSvc auth.AuthService } -// NewServer creates a new pusher server. -func NewServer(hub *Hub, bridge *RedisBridge, authSvc auth.AuthService) *Server { +// NewServer creates a new pusher server. The ctx controls the lifetime of all +// WebSocket connections — when cancelled, all connections are closed gracefully. +func NewServer(ctx context.Context, hub *Hub, bridge *RedisBridge, authSvc auth.AuthService) *Server { return &Server{ + ctx: ctx, hub: hub, bridge: bridge, authSvc: authSvc, @@ -59,7 +62,10 @@ func (s *Server) HandleWebSocket(w http.ResponseWriter, r *http.Request) { slog.Info("websocket connected", "connId", connID, "humanId", session.HumanId) - ctx, cancel := context.WithCancel(r.Context()) + // Use server context, NOT r.Context(). After WebSocket upgrade, the HTTP + // request context can be cancelled by load balancers or Go's HTTP server, + // and nhooyr/websocket permanently closes the conn on any context error. + ctx, cancel := context.WithCancel(s.ctx) defer cancel() // Auto-subscribe to presence channel so this user appears online diff --git a/go/k8s/dev/pusher.yaml b/go/k8s/dev/pusher.yaml index 8548375..3208b18 100644 --- a/go/k8s/dev/pusher.yaml +++ b/go/k8s/dev/pusher.yaml @@ -88,7 +88,7 @@ metadata: name: pusher-backend-policy spec: default: - timeoutSec: 60 + timeoutSec: 3600 connectionDraining: drainingTimeoutSec: 30 targetRef: diff --git a/go/k8s/prod/pusher.yaml b/go/k8s/prod/pusher.yaml index e4649a5..9e5591e 100644 --- a/go/k8s/prod/pusher.yaml +++ b/go/k8s/prod/pusher.yaml @@ -85,7 +85,7 @@ metadata: name: pusher-backend-policy spec: default: - timeoutSec: 60 + timeoutSec: 3600 connectionDraining: drainingTimeoutSec: 30 targetRef: