curb_threadpool 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem "yard"
5
+ gem "redcarpet"
6
+ gem "shoulda", ">= 0"
7
+ gem "rdoc", "~> 3.12"
8
+ gem "bundler", "~> 1.0.0"
9
+ gem "jeweler", "~> 1.8.3"
10
+ gem "rcov", ">= 0", :platforms => :mri_18
11
+ gem "simplecov", :platforms => :mri_19
12
+ end
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2012, Chetan Sarva
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ Redistributions in binary form must reproduce the above copyright notice, this
11
+ list of conditions and the following disclaimer in the documentation and/or
12
+ other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # curb_threadpool
2
+
3
+ A multi-threaded worker pool for Curb.
4
+
5
+ ## Usage
6
+
7
+ ct = Curl::ThreadPool.new
8
+ reqs = []
9
+ 10000.times { |i| ct[i] = "http://localhost/test" }
10
+ responses = ct.exec() # => contains keyed response hash
11
+
12
+ or
13
+
14
+ ct = Curl::ThreadPool.new
15
+ reqs = []
16
+ 10000.times { reqs << "http://localhost/test" }
17
+ ct.get(reqs) # => contains responses in same order as reqs
18
+
19
+ In order to re-use connections opened by the pool, hang on to it:
20
+
21
+ Thread.current[:my_pool] ||= Curl::ThreadPool.new
22
+ Thread.current[:my_pool].get("http://localhost/test")
23
+
24
+ This way, if you frequently make requests to the same host (e.g., an API
25
+ service) then the connections will be kept open as long as possible and
26
+ re-used, speeding up your response time. Curl will automatically
27
+ reconnected when necessary.
28
+
29
+ ## Contributing to curb_threadpool
30
+
31
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
32
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
33
+ * Fork the project.
34
+ * Start a feature/bugfix branch.
35
+ * Commit and push until you are happy with your contribution.
36
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
37
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
38
+
39
+ ## Copyright
40
+
41
+ Copyright (c) 2012 Chetan Sarva. See LICENSE for further details.
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "curb_threadpool"
18
+ gem.homepage = "http://github.com/chetan/curb_threadpool"
19
+ gem.license = "BSD"
20
+ gem.summary = %Q{A multi-threaded worker pool for Curb}
21
+ gem.description = %Q{A multi-threaded worker pool for Curb}
22
+ gem.email = "chetan@pixelcop.net"
23
+ gem.authors = ["Chetan Sarva"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ if Object.const_defined? :Rcov
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
41
+ test.rcov_opts << '--exclude "gems/*"'
42
+ end
43
+ end
44
+
45
+ task :default => :test
46
+
47
+ require 'yard'
48
+ YARD::Rake::YardocTask.new do |t|
49
+ t.options = [ "--files", "README.md,LICENSE" ]
50
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{curb_threadpool}
8
+ s.version = "0.5.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Chetan Sarva"]
12
+ s.date = %q{2012-05-08}
13
+ s.description = %q{A multi-threaded worker pool for Curb}
14
+ s.email = %q{chetan@pixelcop.net}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ "Gemfile",
21
+ "LICENSE",
22
+ "README.md",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "curb_threadpool.gemspec",
26
+ "lib/curb_threadpool.rb",
27
+ "test/helper.rb",
28
+ "test/test_curb_threadpool.rb"
29
+ ]
30
+ s.homepage = %q{http://github.com/chetan/curb_threadpool}
31
+ s.licenses = ["BSD"]
32
+ s.require_paths = ["lib"]
33
+ s.rubygems_version = %q{1.5.0}
34
+ s.summary = %q{A multi-threaded worker pool for Curb}
35
+
36
+ if s.respond_to? :specification_version then
37
+ s.specification_version = 3
38
+
39
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
40
+ s.add_development_dependency(%q<yard>, [">= 0"])
41
+ s.add_development_dependency(%q<redcarpet>, [">= 0"])
42
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
43
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
44
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
45
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
46
+ s.add_development_dependency(%q<rcov>, [">= 0"])
47
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<yard>, [">= 0"])
50
+ s.add_dependency(%q<redcarpet>, [">= 0"])
51
+ s.add_dependency(%q<shoulda>, [">= 0"])
52
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
53
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
54
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
55
+ s.add_dependency(%q<rcov>, [">= 0"])
56
+ s.add_dependency(%q<simplecov>, [">= 0"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<yard>, [">= 0"])
60
+ s.add_dependency(%q<redcarpet>, [">= 0"])
61
+ s.add_dependency(%q<shoulda>, [">= 0"])
62
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
63
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
64
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
65
+ s.add_dependency(%q<rcov>, [">= 0"])
66
+ s.add_dependency(%q<simplecov>, [">= 0"])
67
+ end
68
+ end
69
+
@@ -0,0 +1,104 @@
1
+
2
+ # A multi-threaded worker pool for Curb
3
+ class Curl::ThreadPool
4
+
5
+ attr_reader :results
6
+
7
+ def initialize(size=4)
8
+ @size = size
9
+ reset()
10
+ end
11
+
12
+ # Add a URL to be fetched
13
+ #
14
+ # @param [Object] key to use for request
15
+ # @param [String] url URL to fetch
16
+ def []=(key, url)
17
+ @reqs[key] = url
18
+ end
19
+ alias :add :[]=
20
+
21
+ # Wait for all threads to complete
22
+ def join
23
+ @threads.each { |t| t.join }
24
+ @threads.clear
25
+ end
26
+
27
+ # Close all active Curl connections
28
+ def close
29
+ @clients.each { |c| c.reset(); c.close() } if @clients
30
+ end
31
+
32
+ # Reset the ThreadPool
33
+ def reset
34
+ close()
35
+ @reqs = {}
36
+ @results = {}
37
+ @clients = []
38
+ @threads = []
39
+ @size.times{ @clients << Curl::Easy.new }
40
+ end
41
+
42
+ # Utility method for retrieving a list of URLs
43
+ #
44
+ # @param [Array<String>] urls list of URLs
45
+ # @return [Array] array of response bodies
46
+ def get(urls)
47
+ if urls.nil? or urls.empty? then
48
+ return {}
49
+ end
50
+
51
+ urls = [urls] if not urls.kind_of? Array
52
+ urls.each_with_index do |url, i|
53
+ @reqs[i] = url.to_s
54
+ end
55
+
56
+ results = exec()
57
+
58
+ ret = []
59
+ (0..results.size-1).each do |i|
60
+ ret << results[i]
61
+ end
62
+
63
+ return ret
64
+ end
65
+
66
+ # Execute requests. By default, will block until complete and return results.
67
+ #
68
+ # @param [Boolean] no_block If true, will not wait for requests to finish.
69
+ # (Default=false)
70
+ #
71
+ # @param [Block] block If passed, responses will be passed into the callback
72
+ # instead of being returned directly
73
+ #
74
+ # @return [Hash<Key, String>] Hash of responses, if no block given
75
+ def exec(no_block=false, &block)
76
+ @clients.each do |client|
77
+ @threads << Thread.new do
78
+
79
+ loop do
80
+ break if @reqs.empty?
81
+ (key, url) = @reqs.shift
82
+ client.url = url
83
+ client.http_get
84
+ if block then
85
+ yield(key, client.body_str)
86
+ else
87
+ @results[key] = client.body_str
88
+ end
89
+ end
90
+
91
+ end
92
+ end
93
+
94
+ return {} if no_block
95
+
96
+ join()
97
+ return true if block
98
+
99
+ ret = @results
100
+ @results = {}
101
+ return ret
102
+ end
103
+
104
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'curb_threadpool'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestCurbThreadpool < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: curb_threadpool
3
+ version: !ruby/object:Gem::Version
4
+ hash: 11
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
11
+ platform: ruby
12
+ authors:
13
+ - Chetan Sarva
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-05-08 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: yard
23
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ prerelease: false
33
+ type: :development
34
+ requirement: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: redcarpet
37
+ version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ prerelease: false
47
+ type: :development
48
+ requirement: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: shoulda
51
+ version_requirements: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ prerelease: false
61
+ type: :development
62
+ requirement: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: rdoc
65
+ version_requirements: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ hash: 31
71
+ segments:
72
+ - 3
73
+ - 12
74
+ version: "3.12"
75
+ prerelease: false
76
+ type: :development
77
+ requirement: *id004
78
+ - !ruby/object:Gem::Dependency
79
+ name: bundler
80
+ version_requirements: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ hash: 23
86
+ segments:
87
+ - 1
88
+ - 0
89
+ - 0
90
+ version: 1.0.0
91
+ prerelease: false
92
+ type: :development
93
+ requirement: *id005
94
+ - !ruby/object:Gem::Dependency
95
+ name: jeweler
96
+ version_requirements: &id006 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ hash: 49
102
+ segments:
103
+ - 1
104
+ - 8
105
+ - 3
106
+ version: 1.8.3
107
+ prerelease: false
108
+ type: :development
109
+ requirement: *id006
110
+ - !ruby/object:Gem::Dependency
111
+ name: rcov
112
+ version_requirements: &id007 !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ prerelease: false
122
+ type: :development
123
+ requirement: *id007
124
+ - !ruby/object:Gem::Dependency
125
+ name: simplecov
126
+ version_requirements: &id008 !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ prerelease: false
136
+ type: :development
137
+ requirement: *id008
138
+ description: A multi-threaded worker pool for Curb
139
+ email: chetan@pixelcop.net
140
+ executables: []
141
+
142
+ extensions: []
143
+
144
+ extra_rdoc_files:
145
+ - LICENSE
146
+ - README.md
147
+ files:
148
+ - Gemfile
149
+ - LICENSE
150
+ - README.md
151
+ - Rakefile
152
+ - VERSION
153
+ - curb_threadpool.gemspec
154
+ - lib/curb_threadpool.rb
155
+ - test/helper.rb
156
+ - test/test_curb_threadpool.rb
157
+ has_rdoc: true
158
+ homepage: http://github.com/chetan/curb_threadpool
159
+ licenses:
160
+ - BSD
161
+ post_install_message:
162
+ rdoc_options: []
163
+
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ none: false
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ hash: 3
172
+ segments:
173
+ - 0
174
+ version: "0"
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ none: false
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ hash: 3
181
+ segments:
182
+ - 0
183
+ version: "0"
184
+ requirements: []
185
+
186
+ rubyforge_project:
187
+ rubygems_version: 1.5.0
188
+ signing_key:
189
+ specification_version: 3
190
+ summary: A multi-threaded worker pool for Curb
191
+ test_files: []
192
+