Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Reuse cached session in MRU order, not in LRU

MRU is more server friendly than LRU because it reduces number of cached
sessions when a number of requests drops after an usaage spike.
Closes #68.

With reusing sessions in LRU order, all sessions are equally checked if
it's closed or not, as far as there's a request to the same site.  With
reusing sessions in MRU order, old cold sessions are kept in cache long
time even if there's a request to the same site.  To avoid this leakage,
this commit adds keep_alive_timeout property and let SessionManager
scrub all sessions with checking the timeout for each session.  When the
session expires against the last used time, it's closed and collected.

keep_alive_timeout is 15[sec] by default. The value is from the default
value for KeepAliveTimeout of Apache httpd 2.  This change is related
to #56.
  • Loading branch information...
commit 08ec3adec73e91c704030e5e91611aabd138c07b 1 parent 3f84cd9
@nahi nahi authored
Showing with 12 additions and 3 deletions.
  1. +2 −0  lib/httpclient.rb
  2. +10 −3 lib/httpclient/session.rb
View
2  lib/httpclient.rb
@@ -335,6 +335,8 @@ def attr_proxy(symbol, assignable = false)
attr_proxy(:send_timeout, true)
# Response receiving timeout in sec.
attr_proxy(:receive_timeout, true)
+ # Reuse the same connection within this timeout in sec. from last used.
+ attr_proxy(:keep_alive_timeout, true)
# Negotiation retry count for authentication. 5 by default.
attr_proxy(:protocol_retry_count, true)
# if your ruby is older than 2005-09-06, do not set socket_sync = false to
View
13 lib/httpclient/session.rb
@@ -102,6 +102,7 @@ class SessionManager
attr_accessor :connect_retry
attr_accessor :send_timeout
attr_accessor :receive_timeout
+ attr_accessor :keep_alive_timeout
attr_accessor :read_block_size
attr_accessor :protocol_retry_count
@@ -129,7 +130,8 @@ def initialize(client)
@connect_timeout = 60
@connect_retry = 1
@send_timeout = 120
- @receive_timeout = 60 # For each read_block_size bytes
+ @receive_timeout = 60 # For each read_block_size bytes
+ @keep_alive_timeout = 15 # '15' is from Apache 2 default
@read_block_size = 1024 * 16 # follows net/http change in 1.8.7
@protocol_retry_count = 5
@@ -172,6 +174,7 @@ def reset_all
close_all
end
+ # assert: sess.last_used must not be nil
def keep(sess)
add_cached_session(sess)
end
@@ -233,10 +236,11 @@ def close(dest)
def get_cached_session(uri)
cached = nil
+ now = Time.now
@sess_pool_mutex.synchronize do
new_pool = []
@sess_pool.each do |s|
- if s.invalidated?
+ if s.invalidated? or now > s.last_used + @keep_alive_timeout
s.close # close & remove from the pool
elsif !cached && s.dest.match(uri)
cached = s
@@ -251,7 +255,7 @@ def get_cached_session(uri)
def add_cached_session(sess)
@sess_pool_mutex.synchronize do
- @sess_pool << sess
+ @sess_pool.unshift(sess)
end
end
end
@@ -523,6 +527,7 @@ class Session
attr_accessor :test_loopback_http_response
attr_accessor :transparent_gzip_decompression
+ attr_reader :last_used
def initialize(client, dest, agent_name, from)
@client = client
@@ -561,6 +566,7 @@ def initialize(client, dest, agent_name, from)
@readbuf = nil
@transparent_gzip_decompression = false
+ @last_used = nil
end
# Send a request to the server
@@ -594,6 +600,7 @@ def query(req)
@state = :META if @state == :WAIT
@next_connection = nil
@requests.push(req)
+ @last_used = Time.now
end
def close
Please sign in to comment.
Something went wrong with that request. Please try again.