title: How to kill node.js server connection when client browser exits?
body: <p>I'm trying to write a simple node.js server with Server Sent Event abilities without socket.io. My code runs well enough, but I ran into a huge problem when I was testing it.</p>
  
  <p>If I connect to the node.js server from my browser, it will receive the server events fine. But when I refresh the connection, the same browser will start to receive the event twice. If I refresh n times, the browser will receive data n+1 times.</p>
  
  <p>The most I tried this out with was 16 times (16 refreshes) before I stopped trying to count it.</p>
  
  <p>See the screenshot below of the console from my browser. After the refresh (it tries to make an AJAX call), it will output "SSE persistent connection established!" and afterwards it will start receiving events.</p>
  
  <p>Note the time when the events arrive. I get the event twice at 19:34:07 (it logs to the console twice -- upon receipt of the event and upon writing of the data to the screen; so you can see four logs there).</p>
  
  <p>I also get the event twice at 19:34:12.</p>
  
  <p><img src="https://i.stack.imgur.com/OlBrs.png" alt="client side"></p>
  
  <p>Here's what it looks like at the server side after the client has closed the connection (with source.close() ):</p>
  
  <p><img src="https://i.stack.imgur.com/rky2E.png" alt="server side"></p>
  
  <p>As you can see, it is still trying to send messages to the client! Also, it's trying to send the messages twice (so I know this is a server side problem)!</p>
  
  <p>I know it tries to send twice because it sent two heartbeats when it's only supposed to send once per 30 seconds.</p>
  
  <p>This problem magnifies when open n tabs. What happens is each open tab will receive n*n events. Basically, how I interpret it is this:</p>
  
  <p>Opening the first tab, I subscribe to the server once. Opening the second tab, I subscribe both open tabs to the server once again -- so that's 2 subscriptions per tab. Opening a third tab, I subscribe all three open tabs to the events once more, so 3 subscriptions per tab, total of 9. And so on...</p>
  
  <p>I can't verify this, but my guess is that if I can create one subscription, I should be able to unsubscribe if certain conditions are met (ie, heartbeat fails, I must disconnect).  And the reason this is happening is only because of the following:</p>
  
  <ol>
  <li>I started setInterval once, and an instance of it will forever run unless I stop it, or</li>
  <li>The server is still trying to send data to the client trying to keep the connection open?</li>
  </ol>
  
  <p>As for 1., I've already tried to kill the setInterval with clearInterval, it doesn't work. As for 2, while it's probably impossible, I'm leaning towards believing that...</p>
  
  <p>Here's server side code snippets of just the relevant parts (editing the code after the suggestions from answers):</p>
  
  <pre><code>server = http.createServer(function(req, res){
      heartbeatPulse(res);
  }).listen(8888, '127.0.0.1', 511);
  
  server.on("request", function(req, res){
      console.log("Request Received!");
  
      var route_origin = url.parse(req.url);
  
      if(route_origin.query !== null){
          serveAJAX(res);
      } else {
          serveSSE(res);
          //hbTimerID = timerID.hbID;
          //msgTimerID = timerID.msgID;
      }
  
      req.on("close", function(){
          console.log("close the connection!");
          res.end();
          clearInterval(res['hbID']);
          clearInterval(res['msgID']);
          console.log(res['hbID']);
          console.log(res['msgID']);
      });
  });
  
  var attachListeners = function(res){
      /*
          Adding listeners to the server
          These events are triggered only when the server communicates by SSE
      */
  
      // this listener listens for file changes -- needs more modification to accommodate which file changed, what to write
      server.addListener("file_changed", function(res){
          // replace this with a file reader function
          writeUpdate = res.write("data: {\"date\": \"" + Date() + "\", \"test\": \"nowsssss\", \"i\": " + i++ + "}\n\n");
  
          if(writeUpdate){
              console.log("Sent SSE!");
          } else {
              console.log("SSE failed to send!");
          }
      });
  
      // this listener enables the server to send heartbeats
      server.addListener("hb", function(res){
  
          if(res.write("event: hb\ndata:\nretry: 5000\n\n")){
              console.log("Sent HB!");
          } else {
              // this fails. We can't just close the response, we need to close the connection
              // how to close a connection upon the client closing the browser??
              console.log("HB failed! Closing connection to client...");
              res.end();
              //console.log(http.IncomingMessage.connection);
              //http.IncomingMessage.complete = true;
              clearInterval(res['hbID']);
              clearInterval(res['msgID']);
              console.log(res['hbID']);
              console.log(res['msgID']);
              console.log("\tConnection Closed.");
          }
      });
  }
  
  var heartbeatPulse = function(res){
      res['hbID'] = "";
      res['msgID'] = "";
  
      res['hbID'] = setInterval(function(){
          server.emit("hb", res);
      }, HB_period);
  
      res['msgID'] = setInterval(function(){
          server.emit("file_changed", res);
      }, 5000);
  
      console.log(res['hbID']);
      console.log(res['msgID'])
  
      /*return {
          hbID: hbID,
          msgID: msgID
      };*/
  }
  
  var serveSSE = function(res){
      res.writeHead(200, {
          "Content-Type": "text/event-stream",
          "Cache-Control": "no-cache",
          "Access-Control-Allow-Origin": "*",
          "Connection": "keep-alive"
      });
  
      console.log("Establishing Persistent Connection...");
      if(res.write("event: connector\ndata:\nretry: 5000\n\n")){
          // Only upon receiving the first message will the headers be sent
          console.log("Established Persistent Connection!");
      }
  
      attachListeners(res);
  
      console.log("\tRequested via SSE!");
  }
  </code></pre>
  
  <p>This is largely a self project for learning, so any comments are definitely welcome.</p>