mod_bosh: Instead of a global once-per-second timer add a timer for each session when needed
authorKim Alvefur <zash@zash.se>
Mon, 07 Dec 2015 19:44:08 +0100
changeset 6992 118858bf47cd
parent 6991 329d5fb8a9d3
child 6993 f476e2497568
mod_bosh: Instead of a global once-per-second timer add a timer for each session when needed
plugins/mod_bosh.lua
--- a/plugins/mod_bosh.lua	Thu Dec 10 18:58:30 2015 +0000
+++ b/plugins/mod_bosh.lua	Mon Dec 07 19:44:08 2015 +0100
@@ -63,13 +63,11 @@
 local os_time = os.time;
 
 -- All sessions, and sessions that have no requests open
-local sessions, inactive_sessions = module:shared("sessions", "inactive_sessions");
+local sessions = module:shared("sessions");
 
 -- Used to respond to idle sessions (those with waiting requests)
-local waiting_requests = module:shared("waiting_requests");
 function on_destroy_request(request)
 	log("debug", "Request destroyed: %s", tostring(request));
-	waiting_requests[request] = nil;
 	local session = sessions[request.context.sid];
 	if session then
 		local requests = session.requests;
@@ -83,9 +81,24 @@
 		-- If this session now has no requests open, mark it as inactive
 		local max_inactive = session.bosh_max_inactive;
 		if max_inactive and #requests == 0 then
-			inactive_sessions[session] = os_time() + max_inactive;
+			if session.inactive_timer then
+				session.inactive_timer:stop();
+			end
+			session.inactive_timer = module:add_timer(max_inactive, check_inactive, session, request.context,
+				"BOSH client silent for over "..max_inactive.." seconds");
 			(session.log or log)("debug", "BOSH session marked as inactive (for %ds)", max_inactive);
 		end
+		if session.bosh_wait_timer then
+			session.bosh_wait_timer:stop();
+			session.bosh_wait_timer = nil;
+		end
+	end
+end
+
+function check_inactive(now, session, context, reason)
+	if not sessions.destroyed then
+		sessions[context.sid] = nil;
+		sm_destroy_session(session, reason);
 	end
 end
 
@@ -119,7 +132,7 @@
 	local headers = response.headers;
 	headers.content_type = "text/xml; charset=utf-8";
 
-	if cross_domain and event.request.headers.origin then
+	if cross_domain and request.headers.origin then
 		set_cross_domain_headers(response);
 	end
 
@@ -140,8 +153,14 @@
 	if session then
 		-- Session was marked as inactive, since we have
 		-- a request open now, unmark it
-		if inactive_sessions[session] and #session.requests > 0 then
-			inactive_sessions[session] = nil;
+		if session.inactive_timer and #session.requests > 0 then
+			session.inactive_timer:stop();
+			session.inactive_timer = nil;
+		end
+
+		if session.bosh_wait_timer then
+			session.bosh_wait_timer:stop();
+			session.bosh_wait_timer = nil;
 		end
 
 		local r = session.requests;
@@ -170,7 +189,7 @@
 			-- We're keeping this request open, to respond later
 			log("debug", "Have nothing to say, so leaving request unanswered for now");
 			if session.bosh_wait then
-				waiting_requests[response] = os_time() + session.bosh_wait;
+				session.bosh_wait_timer = module:add_timer(session.bosh_wait, after_bosh_wait, request, session)
 			end
 		end
 
@@ -186,6 +205,11 @@
 	return 400;
 end
 
+function after_bosh_wait(now, request, session)
+	if request.conn then
+		session.send("");
+	end
+end
 
 local function bosh_reset_stream(session) session.notopen = true; end
 
@@ -225,7 +249,6 @@
 		held_request:send(response_body);
 	end
 	sessions[session.sid] = nil;
-	inactive_sessions[session] = nil;
 	sm_destroy_session(session);
 end
 
@@ -407,44 +430,6 @@
 	end
 end
 
-local dead_sessions = module:shared("dead_sessions");
-function on_timer()
-	-- log("debug", "Checking for requests soon to timeout...");
-	-- Identify requests timing out within the next few seconds
-	local now = os_time() + 3;
-	for request, reply_before in pairs(waiting_requests) do
-		if reply_before <= now then
-			log("debug", "%s was soon to timeout (at %d, now %d), sending empty response", tostring(request), reply_before, now);
-			-- Send empty response to let the
-			-- client know we're still here
-			if request.conn then
-				sessions[request.context.sid].send("");
-			end
-		end
-	end
-
-	now = now - 3;
-	local n_dead_sessions = 0;
-	for session, close_after in pairs(inactive_sessions) do
-		if close_after < now then
-			(session.log or log)("debug", "BOSH client inactive too long, destroying session at %d", now);
-			sessions[session.sid]  = nil;
-			inactive_sessions[session] = nil;
-			n_dead_sessions = n_dead_sessions + 1;
-			dead_sessions[n_dead_sessions] = session;
-		end
-	end
-
-	for i=1,n_dead_sessions do
-		local session = dead_sessions[i];
-		dead_sessions[i] = nil;
-		sm_destroy_session(session, "BOSH client silent for over "..session.bosh_max_inactive.." seconds");
-	end
-	return 1;
-end
-module:add_timer(1, on_timer);
-
-
 local GET_response = {
 	headers = {
 		content_type = "text/html";