Skip to content

Commit

Permalink
Reuse cached session in MRU order, not in LRU
Browse files Browse the repository at this point in the history
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
Hiroshi Nakamura committed Oct 13, 2011
1 parent 3f84cd9 commit 08ec3ad
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 3 deletions.
2 changes: 2 additions & 0 deletions lib/httpclient.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions lib/httpclient/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 08ec3ad

Please sign in to comment.