mod_bosh: Instead of a global once-per-second timer add a timer for each session...
authorKim Alvefur <zash@zash.se>
Mon, 7 Dec 2015 18:44:08 +0000 (19:44 +0100)
committerKim Alvefur <zash@zash.se>
Mon, 7 Dec 2015 18:44:08 +0000 (19:44 +0100)
plugins/mod_bosh.lua

index 9e8354fec893ae7711806f1b6e1044006c34f75c..52974f39c9fee6d026f5b3cba677395e85f332fe 100644 (file)
@@ -63,13 +63,11 @@ local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat;
 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 @@ function on_destroy_request(request)
                -- 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 @@ function handle_POST(event)
        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 @@ function handle_POST(event)
        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 @@ function handle_POST(event)
                        -- 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 @@ function handle_POST(event)
        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 @@ local function bosh_close_stream(session, reason)
                held_request:send(response_body);
        end
        sessions[session.sid] = nil;
-       inactive_sessions[session] = nil;
        sm_destroy_session(session);
 end
 
@@ -407,44 +430,6 @@ function stream_callbacks.error(context, error)
        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";