Browse Source

Close stale sessions

New envvar SESSION_TIMEOUT
A session with no activity is cut off after this time
Fixes #56
master
Neil Booth 8 years ago
parent
commit
3d2824218b
  1. 3
      docs/ENV-NOTES
  2. 2
      lib/jsonrpc.py
  3. 1
      server/env.py
  4. 18
      server/protocol.py

3
docs/ENV-NOTES

@ -83,6 +83,9 @@ BANDWIDTH_LIMIT - per-session periodic bandwith usage limit in bytes.
end of each period. Currently the period is
hard-coded to be one hour. The default limit value
is 2 million bytes.
SESSION_TIMEOUT - an integer number of seconds defaulting to 600.
Sessions with no activity for longer than this are
disconnected.
If you want IRC connectivity to advertise your node:

2
lib/jsonrpc.py

@ -79,6 +79,7 @@ class JSONRPC(asyncio.Protocol, LoggedClass):
def __init__(self):
super().__init__()
self.start = time.time()
self.last_recv = self.start
self.bandwidth_start = self.start
self.bandwidth_interval = 3600
self.bandwidth_used = 0
@ -155,6 +156,7 @@ class JSONRPC(asyncio.Protocol, LoggedClass):
if npos == -1:
self.parts.append(data)
break
self.last_recv = time.time()
self.recv_count += 1
tail, data = data[:npos], data[npos + 1:]
parts, self.parts = self.parts, []

1
server/env.py

@ -50,6 +50,7 @@ class Env(LoggedClass):
self.max_subs = self.integer('MAX_SUBS', 250000)
self.max_session_subs = self.integer('MAX_SESSION_SUBS', 50000)
self.bandwidth_limit = self.integer('BANDWIDTH_LIMIT', 2000000)
self.session_timeout = self.integer('SESSION_TIMEOUT', 600)
# IRC
self.irc = self.default('IRC', False)
self.irc_nick = self.default('IRC_NICK', None)

18
server/protocol.py

@ -228,8 +228,11 @@ class ServerManager(util.LoggedClass):
self.next_log_sessions = 0
self.max_subs = env.max_subs
self.subscription_count = 0
self.next_stale_check = 0
self.futures = []
env.max_send = max(350000, env.max_send)
self.logger.info('session timeout: {:,d} seconds'
.format(env.session_timeout))
self.logger.info('session bandwidth limit {:,d} bytes'
.format(env.bandwidth_limit))
self.logger.info('max response size {:,d} bytes'.format(env.max_send))
@ -354,6 +357,7 @@ class ServerManager(util.LoggedClass):
.format(len(self.sessions)))
def add_session(self, session):
self.clear_stale_sessions()
coro = session.serve_requests()
future = asyncio.ensure_future(coro)
self.sessions[session] = future
@ -373,6 +377,20 @@ class ServerManager(util.LoggedClass):
future = self.sessions.pop(session)
future.cancel()
def clear_stale_sessions(self):
'''Cut off sessions that haven't done anything for 10 minutes.'''
now = time.time()
if now > self.next_stale_check:
self.next_stale_check = now + 60
cutoff = now - self.env.session_timeout
stale = [session for session in self.sessions
if session.last_recv < cutoff]
for session in stale:
self.close_session(session)
if stale:
self.logger.info('dropped {:,d} stale connections'
.format(len(stale)))
def new_subscription(self):
if self.subscription_count >= self.max_subs:
raise JSONRPC.RPCError('server subscription limit {:,d} reached'

Loading…
Cancel
Save