diff --git a/docker/haproxy/haproxy.consul.cfg.j2 b/docker/haproxy/haproxy.consul.cfg.j2 index f03e813c0..56762eafc 100644 --- a/docker/haproxy/haproxy.consul.cfg.j2 +++ b/docker/haproxy/haproxy.consul.cfg.j2 @@ -164,8 +164,14 @@ backend node_images {% for host in groups.hnode_images %} server {{host}} {{host}}.node.nyc1.consul:8088 {% endfor %} + backend node_socket balance roundrobin + option http-server-close + timeout client 120s + timeout server 120s + timeout connect 10s + timeout tunnel 3600s default-server check inter 2000ms resolvers consul resolve-prefer ipv4 resolve-opts allow-dup-ip init-addr none {% for host in groups.hnode_socket %} server {{host}} {{host}}.node.nyc1.consul:8008 diff --git a/node/unread_counts.coffee b/node/unread_counts.coffee index a217d9363..ac9fbcf28 100644 --- a/node/unread_counts.coffee +++ b/node/unread_counts.coffee @@ -61,10 +61,16 @@ unread_counts = (server) => io = require('socket.io')(server, { path: "/v3/socket.io", - pingTimeout: 60000, # Increase ping timeout to 60 seconds - pingInterval: 25000, # Send ping every 25 seconds - connectTimeout: 45000, # Connection timeout - transports: ['websocket'], # Prefer websocket transport + pingTimeout: 120000, # Increased from 60s to 120s + pingInterval: 30000, # Increased from 25s to 30s + connectTimeout: 60000, # Increased from 45s to 60s + transports: ['websocket'], # Prefer websocket transport + maxHttpBufferSize: 1e8, # Increase buffer size to 100MB + cors: { + origin: "*", + methods: ["GET", "POST"] + }, + allowEIO3: true, # Allow compatibility with Socket.IO v3 clients adapter: require('@socket.io/redis-adapter').createAdapter(pub_client, sub_client) }) @@ -105,9 +111,13 @@ unread_counts = (server) => # Store socket data for tracking socket.data = { ip: ip, - socket_id: socket_id + socket_id: socket_id, + connected_at: Date.now() } + # Set a longer ping timeout for this socket + socket.conn.pingTimeout = 120000 + socket.conn.on 'error', (err) -> log.debug "Socket #{socket_id} - connection error: #{err}" @@ -118,12 +128,17 @@ unread_counts = (server) => # Store user data directly on the socket for access during disconnect socket.data.feeds = feeds socket.data.username = username + socket.data.subscribed_at = Date.now() log.info username, "Connecting (#{feeds.length} feeds, #{ip}), (#{io.engine.clientsCount} connected) #{if SECURE then "(SSL)" else ""}" # Track connections by username for debugging active_connections[username] = active_connections[username] || {} - active_connections[username][socket_id] = true + active_connections[username][socket_id] = { + connected_at: socket.data.connected_at, + subscribed_at: socket.data.subscribed_at, + feed_count: feeds.length + } log.debug "#{username} now has #{Object.keys(active_connections[username]).length} active connections, adding #{socket_id}" if not username @@ -157,8 +172,15 @@ unread_counts = (server) => feeds = socket.data.feeds ip = socket.data.ip socket_id = socket.data.socket_id + connected_at = socket.data.connected_at + subscribed_at = socket.data.subscribed_at - log.debug "Socket #{socket_id} disconnected: #{reason}, username: #{username}" + # Calculate connection duration + now = Date.now() + connection_duration = now - (connected_at || now) + subscription_duration = if subscribed_at then (now - subscribed_at) else 0 + + log.debug "Socket #{socket_id} disconnected: #{reason}, username: #{username}, connection duration: #{connection_duration}ms, subscription duration: #{subscription_duration}ms" # Update connection tracking if username and active_connections[username] diff --git a/node/unread_counts.js b/node/unread_counts.js index 8403d1add..a062fb54d 100644 --- a/node/unread_counts.js +++ b/node/unread_counts.js @@ -66,10 +66,16 @@ }); io = require('socket.io')(server, { path: "/v3/socket.io", - pingTimeout: 60000, // Increase ping timeout to 60 seconds - pingInterval: 25000, // Send ping every 25 seconds - connectTimeout: 45000, // Connection timeout + pingTimeout: 120000, // Increased from 60s to 120s + pingInterval: 30000, // Increased from 25s to 30s + connectTimeout: 60000, // Increased from 45s to 60s transports: ['websocket'], // Prefer websocket transport + maxHttpBufferSize: 1e8, // Increase buffer size to 100MB + cors: { + origin: "*", + methods: ["GET", "POST"] + }, + allowEIO3: true, // Allow compatibility with Socket.IO v3 clients adapter: require('@socket.io/redis-adapter').createAdapter(pub_client, sub_client) }); // Setup Redis error handling and reconnection @@ -111,8 +117,12 @@ // Store socket data for tracking socket.data = { ip: ip, - socket_id: socket_id + socket_id: socket_id, + connected_at: Date.now() }; + + // Set a longer ping timeout for this socket + socket.conn.pingTimeout = 120000; socket.conn.on('error', function(err) { return log.debug(`Socket ${socket_id} - connection error: ${err}`); }); @@ -124,11 +134,16 @@ // Store user data directly on the socket for access during disconnect socket.data.feeds = feeds; socket.data.username = username; + socket.data.subscribed_at = Date.now(); log.info(username, `Connecting (${feeds.length} feeds, ${ip}), (${io.engine.clientsCount} connected) ${SECURE ? "(SSL)" : ""}`); // Track connections by username for debugging active_connections[username] = active_connections[username] || {}; - active_connections[username][socket_id] = true; + active_connections[username][socket_id] = { + connected_at: socket.data.connected_at, + subscribed_at: socket.data.subscribed_at, + feed_count: feeds.length + }; log.debug(`${username} now has ${Object.keys(active_connections[username]).length} active connections, adding ${socket_id}`); if (!username) { return; @@ -163,13 +178,20 @@ }); }); return socket.on('disconnect', function(reason) { - var feeds, ref, username; + var connected_at, connection_duration, feeds, now, ref, subscribed_at, subscription_duration, username; // Use the data stored on the socket username = socket.data.username; feeds = socket.data.feeds; ip = socket.data.ip; socket_id = socket.data.socket_id; - log.debug(`Socket ${socket_id} disconnected: ${reason}, username: ${username}`); + connected_at = socket.data.connected_at; + subscribed_at = socket.data.subscribed_at; + + // Calculate connection duration + now = Date.now(); + connection_duration = now - (connected_at || now); + subscription_duration = subscribed_at ? now - subscribed_at : 0; + log.debug(`Socket ${socket_id} disconnected: ${reason}, username: ${username}, connection duration: ${connection_duration}ms, subscription duration: ${subscription_duration}ms`); // Update connection tracking if (username && active_connections[username]) {