lazy_connection_pool 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NTI4OGY1M2Y5OGQ4ZDliZmJlMTEzNzg2MWJhZGU5YzI3YTlkODJmZA==
5
+ data.tar.gz: !binary |-
6
+ MTVhM2I2YWY5N2NjYWNkMzdmYTUwMWUwY2M0M2M0ZWU5Y2QwN2RiMg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NDY0YjI0ZjQ0ZmFjZTVmNDg5MjAwODRlM2M5MWI2ZDJlNDhlM2NjYmFkY2Nh
10
+ NzJhNWI1Y2JjNDZhMTc3Mzk1MzdlYjI5ZTFhYTcwNmU5MDY3NDAyYzg2YTgx
11
+ MmUxYWFlYTg5ZjRmOWFmM2RhODYzYjA3OTVhODIzMjIzMDI2ODU=
12
+ data.tar.gz: !binary |-
13
+ OTQ4YzA5Y2RkOGQxZTQyMWRhOTBkYmJjODhlM2EyYmExZTEyOGFmNjg4Mzdj
14
+ Y2VhMGM0NDE3MmRkYzVhNTNhNzFhOWQyNWZlNDdjMGU0YjkxOTJjNzBhMWUw
15
+ NzJkYmI4MzQ4M2VmOTE2NTYyZTc4ZmFhNTZiMzczYWNiNmRiYTg=
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .*.sw?
2
+
data/LICENSE.md ADDED
@@ -0,0 +1,25 @@
1
+ LazyConnectionPool License
2
+ ==========================
3
+
4
+ LazyConnectionPool is provided as-is, with the hopes (but not the promise)
5
+ that you find it useful. No warranties are provided, express or implied.
6
+
7
+ The license may change in the future to be more restrictive, but as of
8
+ this commit, you can copy, include, fork, or redistribute the code, in
9
+ whole or in part, in source or (somehow) compiled, with the request that
10
+ source distributions mention the originating webpage and a description of
11
+ how much the code has changed since you got your hands on it.
12
+
13
+ For example:
14
+
15
+ "This code was originally based on LazyConnectionPool, with
16
+ some minor fixes"
17
+
18
+ or,
19
+
20
+ "copied from LazyConnectionPool, and totally rewritten."
21
+
22
+ If you rewrite it so significantly as to be unrecognizable, this request
23
+ is waived. Please use your best judgement as to what "unrecognizeable"
24
+ means.
25
+
data/README.md ADDED
@@ -0,0 +1,109 @@
1
+ LazyConnectionPooler
2
+ ====================
3
+
4
+ A lazy connection pooler for Ruby.
5
+
6
+ This gem is meant to provide functionality similar to Mike Perham's lovely
7
+ [connection_pool](http://github.com/mperham/connection_pool), with the
8
+ twist that connections will be lazily created whenever there's a shortage
9
+ in the pool. It is not, however, meant to be a drop-in replacement for
10
+ that library.
11
+
12
+ I've tested this lightly under CRuby 1.9.3 and JRuby 1.7.10, and it doesn't
13
+ appear to deadlock or step on itself, even when running hundreds of threads
14
+ battling for a handful of connections. But my testing should hardly be a
15
+ promise that it's bug-free, or even functional.
16
+
17
+ Usage
18
+ =====
19
+
20
+ The documentation is, uhm, coming real soon now. The following will have
21
+ to suffice in the meantime.
22
+
23
+ Pool creation
24
+ -------------
25
+
26
+ Initiate a pool, passing in a block that'll be used to initialize new
27
+ connections:
28
+
29
+ pool = LazyConnectionPool.new {
30
+ Net::HTTP.new('localhost')
31
+ }
32
+
33
+ Connection usage: inline
34
+ ------------------------
35
+
36
+ Your new `LazyConnectionPool` object's `#get` method can take a block. It
37
+ will pass your block a connection:
38
+
39
+ response = pool.get { |sock|
40
+ sock.get('/')
41
+ }
42
+
43
+ When used this way, `#get` will return te result of your block. If your
44
+ block raises any exceptions, the connection will still be returned to the
45
+ pool, and the exception will be yours to handle.
46
+
47
+ Connection usage: get/release
48
+ -----------------------------
49
+
50
+ You can also request a connection, then release it when you're done with
51
+ it, by calling `#get` without a block:
52
+
53
+ sock = pool.get
54
+ response = sock.get('/')
55
+ pool.release(sock)
56
+
57
+ Of course, if you don't ever `#release` your connection, it'll just leak
58
+ onto the floor.
59
+
60
+ Pool limits
61
+ -----------
62
+
63
+ You can optionally limit the size of the pool:
64
+
65
+ pool.poolsize = 16
66
+
67
+ The default is a limit of `-1`, which is unlimited. If you specify `0` as
68
+ a limit, no pool objects will be available.
69
+
70
+ Blocking requests
71
+ -----------------
72
+
73
+ If you run out of connections in the pool, such that you run into your
74
+ `poolsize` limit, `#get` will block until a connection is available.
75
+ `#get` takes one optional boolean argument, indicating whether it should
76
+ wait for a connection to become available. If it's false, it'll return
77
+ `nil`. Note that if you use a block with `#get` and it also potentially
78
+ returns `nil`, it could be difficult to differentiate between the two
79
+ conditions, as below:
80
+
81
+ body = pool.get(false) { |sock|
82
+ response = sock.get('/')
83
+ if response.code.to_i == 200
84
+ JSON.parse(response.body)
85
+ end
86
+ }
87
+
88
+ Would it have blocked? Did it connect but the response was something other
89
+ than a 200? The world may never know.
90
+
91
+ Unhealthy connections
92
+ ---------------------
93
+
94
+ LazyConnectionPool assumes that the connections it hands out are healthy,
95
+ or can be made healthy without replacing the connection object. If this
96
+ isn't true, LazyConnectionPool is not for you. Your code should detect and
97
+ heal the connection object whenever needed.
98
+
99
+ Shrinking the pool
100
+ ------------------
101
+
102
+ LazyConnectionPool adds connections to deal with shortages; it does not
103
+ reap them again, unless `poolsize` shrinks somehow.
104
+
105
+ Contributions
106
+ =============
107
+
108
+ Bug? Feature? Contributions of any kind: Send me a pull request.
109
+
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new { |gem|
2
+ gem.name = "lazy_connection_pool"
3
+ gem.version = "1.0.0"
4
+ gem.platform = Gem::Platform::RUBY
5
+ gem.authors = ["Joel Boutros"]
6
+ gem.licenses = [ 'BSD' ]
7
+
8
+ gem.homepage = "http://github.com/jaydeebee/lazy_connection_pool"
9
+ gem.summary = "A lazy connection pooler for Ruby"
10
+ gem.description = "A lazy connection pooler for Ruby. Supports lazy connection allocation and dynamic pool sizing."
11
+
12
+ gem.required_rubygems_version = ">= 1.3.6"
13
+
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.executables = []
16
+
17
+ gem.require_path = 'lib'
18
+ }
19
+
@@ -0,0 +1,107 @@
1
+ #
2
+ # LazyConnectionPool
3
+ #
4
+ # A connection pool that lazily creates connections and can be
5
+ # resized dynamically. It attempts optimistic thread-safety.
6
+ #
7
+
8
+ require 'thread'
9
+
10
+ class LazyConnectionPool
11
+ def initialize(poolsize=-1, &block)
12
+ if block.nil?
13
+ raise ArgumentError, "LazyConnectionPool requires a block"
14
+ end
15
+
16
+ @max_pool_size = poolsize
17
+ @cur_pool_size = 0
18
+ @block = block
19
+ @pool = Queue.new
20
+ @mutex = Mutex.new
21
+ end
22
+
23
+ def poolsize=(poolsize)
24
+ to_release = 0
25
+
26
+ @mutex.synchronize {
27
+ @max_pool_size = poolsize
28
+ if @max_pool_size >= 0
29
+ to_release = (@max_pool_size - @cur_pool_size)
30
+ to_release = @pool.num_waiting if @pool.num_waiting < to_release
31
+ to_release = 0 if to_release < 0
32
+ else
33
+ to_release = @pool.num_waiting
34
+ end
35
+ }
36
+
37
+ if to_release > 0
38
+ to_release.times { |x|
39
+ self.release @block.call
40
+ }
41
+ end
42
+
43
+ return @max_pool_size
44
+ end
45
+
46
+ def poolsize
47
+ @max_pool_size
48
+ end
49
+
50
+ def get(should_wait=true, &block)
51
+ cx = nil
52
+
53
+ # get a cx from the pool
54
+ begin
55
+ # see if we can get one. don't wait if we can't.
56
+ cx = @pool.pop(true)
57
+ rescue ThreadError
58
+ # We did not get one. Can we grow?
59
+ if @max_pool_size < 0 or @cur_pool_size < @max_pool_size
60
+ @mutex.synchronize {
61
+ @cur_pool_size += 1
62
+ if @max_pool_size >= 0 and @cur_pool_size > @max_pool_size
63
+ # back out of our creation (unwind after detecting we lost a
64
+ # a comparison race condition)
65
+ @cur_pool_size -= 1
66
+ else
67
+ cx = @block.call
68
+ end
69
+ }
70
+ end
71
+ end
72
+
73
+ if cx.nil?
74
+ begin
75
+ cx = @pool.pop(!should_wait)
76
+ rescue ThreadError
77
+ return nil
78
+ end
79
+ end
80
+
81
+ # now we have a cx.
82
+ if block.nil?
83
+ return cx
84
+ end
85
+
86
+ begin
87
+ r = yield cx
88
+ ensure
89
+ self.release(cx)
90
+ end
91
+ return r
92
+ end
93
+
94
+ def release(cx)
95
+ if @max_pool_size < 0 or (@max_pool_size > 0 and @cur_pool_size <= @max_pool_size)
96
+ @pool.push cx
97
+ else
98
+ @mutex.synchronize {
99
+ @cur_pool_size -= 1
100
+ @cur_pool_size = 0 if @cur_pool_size < 0
101
+ }
102
+ # XXX: close cx somehow?
103
+ end
104
+ nil
105
+ end
106
+ end
107
+
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lazy_connection_pool
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Joel Boutros
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A lazy connection pooler for Ruby. Supports lazy connection allocation
14
+ and dynamic pool sizing.
15
+ email:
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .gitignore
21
+ - LICENSE.md
22
+ - README.md
23
+ - lazy_connection_pool.gemspec
24
+ - lib/lazy_connection_pool.rb
25
+ homepage: http://github.com/jaydeebee/lazy_connection_pool
26
+ licenses:
27
+ - BSD
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: 1.3.6
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.1.11
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: A lazy connection pooler for Ruby
49
+ test_files: []