tlconnor-spawn 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *~
2
+ *.gem
data/CHANGELOG ADDED
@@ -0,0 +1,55 @@
1
+ v0.1 - 2007/09/13
2
+
3
+ initial version
4
+
5
+ --------------------------------------------------
6
+ v0.2 - 2007/09/28
7
+
8
+ * return PID of the child process
9
+ * added ":detach => false" option
10
+
11
+ --------------------------------------------------
12
+ v0.3 - 2007/10/15
13
+
14
+ * added ':method => :thread' for threaded spawns
15
+ * removed ':detach => false' option in favor of more generic implementation
16
+ * added ability to set configuration of the form 'Spawn::method :thread'
17
+ * added patch to ActiveRecord::Base to allow for more efficient reconnect in child processes
18
+ * added monkey patch for http://dev.rubyonrails.org/ticket/7579
19
+ * added wait() method to wait for spawned code blocks
20
+ * don't allow threading if allow_concurrency=false
21
+
22
+ --------------------------------------------------
23
+ v0.4 - 2008/1/26
24
+
25
+ * default to :thread on windows, still :fork on all other platforms
26
+ * raise exception when used with :method=>:true and allow_concurrency != true
27
+
28
+ --------------------------------------------------
29
+ v0.5 - 2008/3/1
30
+ * also default to :thread on JRuby (java)
31
+ * added new :method => :yield which doesn't fork or thread, this is useful for testing
32
+ * fixed problem with connections piling up on PostgreSQL
33
+
34
+ --------------------------------------------------
35
+ v0.6 - 2008/04/21
36
+ * only apply clear_reloadable_connections patch on Rails 1.x (7579 fixed in Rails 2.x)
37
+ * made it more responsive in more environments by disconnecting from the listener socket in the forked process
38
+
39
+ --------------------------------------------------
40
+ v0.7 - 2008/04/24
41
+ * more generic mechanism for closing resources after fork
42
+ * check for existence of Mongrel before patching it
43
+
44
+ --------------------------------------------------
45
+ v0.8 - 2008/05/02
46
+ * call exit! within the ensure block so that at_exit handlers aren't called on exceptions
47
+ * set logger from RAILS_DEFAULT_LOGGER if available, else STDERR
48
+
49
+ --------------------------------------------------
50
+ v0.9 - 2008/05/11
51
+ * added ability to set nice level for child process
52
+
53
+ --------------------------------------------------
54
+ v1.0 - 2010/10/09
55
+ * merged edged to master, let's call this version 1.0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2007 Tom Anderson (tom@squeat.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,193 @@
1
+ # Spawn
2
+
3
+ This plugin provides a 'spawn' method to easily fork OR thread long-running sections of
4
+ code so that your application can return results to your users more quickly.
5
+ This plugin works by creating new database connections in ActiveRecord::Base for the
6
+ spawned block.
7
+
8
+ The plugin also patches ActiveRecord::Base to handle some known bugs when using
9
+ threads (see lib/patches.rb).
10
+
11
+ ## Installation
12
+
13
+ To install the plugin from the master branch (recommended).
14
+
15
+ script/plugin install git://github.com/tra/spawn.git
16
+
17
+ If you want to install the plugin from the 'edge' branch (latest development):
18
+
19
+ script/plugin install git://github.com/tra/spawn.git -r edge
20
+
21
+ If you are unfortunate enough to be stuck on Rails 1.x, then it is recommended you
22
+ stick with v1.0 of this plugin (Rails 1.x won't be supported in future versions but
23
+ it might still work if you're lucky). To install this version:
24
+
25
+ script/plugin install git://github.com/tra/spawn.git -r master:v1.0
26
+
27
+ ## Usage
28
+
29
+ Here's a simple example of how to demonstrate the spawn plugin.
30
+ In one of your controllers, insert this code (after installing the plugin of course):
31
+
32
+ spawn do
33
+ logger.info("I feel sleepy...")
34
+ sleep 11
35
+ logger.info("Time to wake up!")
36
+ end
37
+
38
+ If everything is working correctly, your controller should finish quickly then you'll see
39
+ the last log message several seconds later.
40
+
41
+ If you need to wait for the spawned processes/threads, then pass the objects returned by
42
+ spawn to Spawn::wait(), like this:
43
+
44
+ N.times do |i|
45
+ # spawn N blocks of code
46
+ spawn_ids[i] = spawn do
47
+ something(i)
48
+ end
49
+ end
50
+ # wait for all N blocks of code to finish running
51
+ wait(spawn_ids)
52
+
53
+ ## Options
54
+
55
+ The options you can pass to spawn are:
56
+
57
+ <table>
58
+ <tr><th>Option</th><th>Values</th></tr>
59
+ <tr><td>:method</td><td>:fork, :thread, :yield</td></tr>
60
+ <tr><td>:nice</td><td>integer value 0-19, 19 = really nice</td></tr>
61
+ <tr><td>:kill</td><td>boolean value indicating whether the parent should kill the spawned process
62
+ when it exits (only valid when :method => :fork)</td></tr>
63
+ <tr><td>:argv</td><td>string to override the process name</td></tr>
64
+ </table>
65
+
66
+ Any option to spawn can be set as a default so that you don't have to pass them in
67
+ to every call of spawn. To configure the spawn default options, add a line to
68
+ your configuration file(s) like this:
69
+
70
+ Spawn::default_options {:method => :thread}
71
+
72
+ If you don't set any default options, the :method will default to :fork. To
73
+ specify different values for different environments, add the default_options call to
74
+ he appropriate environment file (development.rb, test.rb). For testing you can set
75
+ the default :method to :yield so that the code is run inline.
76
+
77
+ # in environment.rb
78
+ Spawn::method :method => :fork, :nice => 7
79
+ # in test.rb, will override the environment.rb setting
80
+ Spawn::method :method => :yield
81
+
82
+ This allows you to set your production and development environments to use different
83
+ methods according to your needs.
84
+
85
+ ### be nice
86
+
87
+ If you want your forked child to run at a lower priority than the parent process, pass in
88
+ the :nice option like this:
89
+
90
+ spawn(:nice => 7) do
91
+ do_something_nicely
92
+ end
93
+
94
+ ### fork me
95
+
96
+ By default, spawn will use the fork to spawn child processes. You can configure it to
97
+ do threading either by telling the spawn method when you call it or by configuring your
98
+ environment.
99
+ For example, this is how you can tell spawn to use threading on the call,
100
+
101
+ spawn(:method => :thread) do
102
+ something
103
+ end
104
+
105
+ For older versions of Rails (1.x), when using the :thread setting, spawn will check to
106
+ make sure that you have set allow_concurrency=true in your configuration. If you
107
+ want this setting then put this line in one of your environment config files:
108
+
109
+ config.active_record.allow_concurrency = true
110
+
111
+ If it is not set, then spawn will raise an exception.
112
+
113
+ ### kill or be killed
114
+
115
+ Depending on your application, you may want the children processes to go away when
116
+ the parent process exits. By default spawn lets the children live after the
117
+ parent dies. But you can tell it to kill the children by setting the :kill option
118
+ to true.
119
+
120
+ ### a process by any other name
121
+
122
+ If you'd like to be able to identify which processes are spawned by looking at the
123
+ output of ps then set the :argv option with a string of your choice.
124
+ You should then be able to see this string as the process name when
125
+ listing the running processes (ps).
126
+
127
+ For example, if you do something like this,
128
+
129
+ 3.times do |i|
130
+ spawn(:argv => "spawn -#{i}-") do
131
+ something(i)
132
+ end
133
+ end
134
+
135
+ then in the shell,
136
+
137
+ $ ps -ef | grep spawn
138
+ 502 2645 2642 0 0:00.01 ttys002 0:00.02 spawn -0-
139
+ 502 2646 2642 0 0:00.02 ttys002 0:00.02 spawn -1-
140
+ 502 2647 2642 0 0:00.02 ttys002 0:00.03 spawn -2-
141
+
142
+ The length of the process name may be limited by your OS so you might want to experiment
143
+ to see how long it can be (it may be limited by the length of the original process name).
144
+
145
+ ## Forking vs. Threading
146
+
147
+ There are several tradeoffs for using threading vs. forking. Forking was chosen as the
148
+ default primarily because it requires no configuration to get it working out of the box.
149
+
150
+ Forking advantages:
151
+
152
+ - more reliable? - the ActiveRecord code is generally not deemed to be thread-safe.
153
+ Even though spawn attempts to patch known problems with the threaded implementation,
154
+ there are no guarantees. Forking is heavier but should be fairly reliable.
155
+ - keep running - this could also be a disadvantage, but you may find you want to fork
156
+ off a process that could have a life longer than its parent. For example, maybe you
157
+ want to restart your server without killing the spawned processes.
158
+ We don't necessarily condone this (i.e. haven't tried it) but it's technically possible.
159
+ - easier - forking works out of the box with spawn, threading requires you set
160
+ allow_concurrency=true (for older versions of Rails).
161
+ Also, beware of automatic reloading of classes in development
162
+ mode (config.cache_classes = false).
163
+
164
+ Threading advantages:
165
+ - less filling - threads take less resources... how much less? it depends. Some
166
+ flavors of Unix are pretty efficient at forking so the threading advantage may not
167
+ be as big as you think... but then again, maybe it's more than you think. ;-)
168
+ - debugging - you can set breakpoints in your threads
169
+
170
+ ## Acknowledgements
171
+
172
+ This plugin was initially inspired by Scott Persinger's blog post on how to use fork
173
+ in rails for background processing.
174
+ http://geekblog.vodpod.com/?p=26
175
+
176
+ Further inspiration for the threading implementation came from Jonathon Rochkind's
177
+ blog post on threading in rails.
178
+ http://bibwild.wordpress.com/2007/08/28/threading-in-rails/
179
+
180
+ Also thanks to all who have helped debug problems and suggest improvements
181
+ including:
182
+
183
+ - Ahmed Adam, Tristan Schneiter, Scott Haug, Andrew Garfield, Eugene Otto, Dan Sharp,
184
+ Olivier Ruffin, Adrian Duyzer, Cyrille Labesse
185
+
186
+ - Garry Tan, Matt Jankowski (Rails 2.2.x fixes), Mina Naguib (Rails 2.3.6 fix)
187
+
188
+ - Tim Kadom, Mauricio Marcon Zaffari, Danial Pearce, Hongli Lai, Scott Wadden
189
+ (passenger fixes)
190
+
191
+ - &lt;your name here&gt;
192
+
193
+ Copyright (c) 2007-present Tom Anderson (tom@squeat.com), see LICENSE
data/lib/spawn.rb ADDED
@@ -0,0 +1,6 @@
1
+ require File.join(File.dirname(__FILE__), 'spawn', 'spawn')
2
+ require File.join(File.dirname(__FILE__), 'spawn', 'patches')
3
+
4
+ ActiveRecord::Base.send :include, Spawn
5
+ ActionController::Base.send :include, Spawn
6
+ ActiveRecord::Observer.send :include, Spawn
@@ -0,0 +1,109 @@
1
+ # see activerecord/lib/active_record/connection_adaptors/abstract/connection_specification.rb
2
+ class ActiveRecord::Base
3
+ # reconnect without disconnecting
4
+ if Spawn::RAILS_2_2
5
+ def self.spawn_reconnect(klass=self)
6
+ # keep ancestors' connection_handlers around to avoid them being garbage collected in the forked child
7
+ @@ancestor_connection_handlers ||= []
8
+ @@ancestor_connection_handlers << self.connection_handler
9
+ self.connection_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
10
+
11
+ establish_connection
12
+ end
13
+ else
14
+ def self.spawn_reconnect(klass=self)
15
+ spec = @@defined_connections[klass.name]
16
+ konn = active_connections[klass.name]
17
+ # remove from internal arrays before calling establish_connection so that
18
+ # the connection isn't disconnected when it calls AR::Base.remove_connection
19
+ @@defined_connections.delete_if { |key, value| value == spec }
20
+ active_connections.delete_if { |key, value| value == konn }
21
+ establish_connection(spec ? spec.config : nil)
22
+ end
23
+ end
24
+
25
+ # this patch not needed on Rails 2.x and later
26
+ if Spawn::RAILS_1_x
27
+ # monkey patch to fix threading problems,
28
+ # see: http://dev.rubyonrails.org/ticket/7579
29
+ def self.clear_reloadable_connections!
30
+ if @@allow_concurrency
31
+ # Hash keyed by thread_id in @@active_connections. Hash of hashes.
32
+ @@active_connections.each do |thread_id, conns|
33
+ conns.each do |name, conn|
34
+ if conn.requires_reloading?
35
+ conn.disconnect!
36
+ @@active_connections[thread_id].delete(name)
37
+ end
38
+ end
39
+ end
40
+ else
41
+ # Just one level hash, no concurrency.
42
+ @@active_connections.each do |name, conn|
43
+ if conn.requires_reloading?
44
+ conn.disconnect!
45
+ @@active_connections.delete(name)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ # see mongrel/lib/mongrel.rb
54
+ # it's possible that this is not defined if you're running outside of mongrel
55
+ # examples: ./script/runner or ./script/console
56
+ if defined? Mongrel::HttpServer
57
+ class Mongrel::HttpServer
58
+ # redefine Montrel::HttpServer::process_client so that we can intercept
59
+ # the socket that is being used so Spawn can close it upon forking
60
+ alias_method :orig_process_client, :process_client
61
+ def process_client(client)
62
+ Spawn.resources_to_close(client, @socket)
63
+ orig_process_client(client)
64
+ end
65
+ end
66
+ end
67
+
68
+ need_passenger_patch = true
69
+ if defined? PhusionPassenger::VERSION_STRING
70
+ # The VERSION_STRING variable was defined sometime after 2.1.0.
71
+ # We don't need passenger patch for 2.2.2 or later.
72
+ pv = PhusionPassenger::VERSION_STRING.split('.').collect{|s| s.to_i}
73
+ need_passenger_patch = pv[0] < 2 || (pv[0] == 2 && (pv[1] < 2 || (pv[1] == 2 && pv[2] < 2)))
74
+ end
75
+
76
+ if need_passenger_patch
77
+ # Patch for work with passenger < 2.1.0
78
+ if defined? Passenger::Railz::RequestHandler
79
+ class Passenger::Railz::RequestHandler
80
+ alias_method :orig_process_request, :process_request
81
+ def process_request(headers, input, output)
82
+ Spawn.resources_to_close(input, output)
83
+ orig_process_request(headers, input, output)
84
+ end
85
+ end
86
+ end
87
+
88
+ # Patch for work with passenger >= 2.1.0
89
+ if defined? PhusionPassenger::Railz::RequestHandler
90
+ class PhusionPassenger::Railz::RequestHandler
91
+ alias_method :orig_process_request, :process_request
92
+ def process_request(headers, input, output)
93
+ Spawn.resources_to_close(input, output)
94
+ orig_process_request(headers, input, output)
95
+ end
96
+ end
97
+ end
98
+
99
+ # Patch for passenger with Rails >= 2.3.0 (uses rack)
100
+ if defined? PhusionPassenger::Rack::RequestHandler
101
+ class PhusionPassenger::Rack::RequestHandler
102
+ alias_method :orig_process_request, :process_request
103
+ def process_request(headers, input, output)
104
+ Spawn.resources_to_close(input, output)
105
+ orig_process_request(headers, input, output)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,211 @@
1
+ module Spawn
2
+ RAILS_1_x = (::Rails::VERSION::MAJOR == 1) unless defined?(RAILS_1_x)
3
+ RAILS_2_2 = (::Rails::VERSION::MAJOR > 2 || (::Rails::VERSION::MAJOR == 2 && ::Rails::VERSION::MINOR >= 2)) unless defined?(RAILS_2_2)
4
+
5
+ @@default_options = {
6
+ # default to forking (unless windows or jruby)
7
+ :method => ((RUBY_PLATFORM =~ /(win32|java)/) ? :thread : :fork),
8
+ :nice => nil,
9
+ :kill => false,
10
+ :argv => nil
11
+ }
12
+
13
+ # things to close in child process
14
+ @@resources = []
15
+ # in some environments, logger isn't defined
16
+ @@logger = defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : Logger.new(STDERR)
17
+ # forked children to kill on exit
18
+ @@punks = []
19
+
20
+ # Set the options to use every time spawn is called unless specified
21
+ # otherwise. For example, in your environment, do something like
22
+ # this:
23
+ # Spawn::default_options = {:nice => 5}
24
+ # to default to using the :nice option with a value of 5 on every call.
25
+ # Valid options are:
26
+ # :method => (:thread | :fork | :yield)
27
+ # :nice => nice value of the forked process
28
+ # :kill => whether or not the parent process will kill the
29
+ # spawned child process when the parent exits
30
+ # :argv => changes name of the spawned process as seen in ps
31
+ def self.default_options(options = {})
32
+ @@default_options.merge!(options)
33
+ @@logger.info "spawn> default options = #{options.inspect}"
34
+ end
35
+
36
+ # @deprecated - please use Spawn::default_options(:method => ) instead
37
+ # add calls to this in your environment.rb to set your configuration, for example,
38
+ # to use forking everywhere except your 'development' environment:
39
+ # Spawn::method :fork
40
+ # Spawn::method :thread, 'development'
41
+ def self.method(method, env = nil)
42
+ @@logger.warn "spawn> please use Spawn::default_options(:method => #{method}) instead of Spawn::method"
43
+ if !env || env == RAILS_ENV
44
+ default_options :method => method
45
+ end
46
+ end
47
+
48
+ # set the resources to disconnect from in the child process (when forking)
49
+ def self.resources_to_close(*resources)
50
+ @@resources = resources
51
+ end
52
+
53
+ # close all the resources added by calls to resource_to_close
54
+ def self.close_resources
55
+ @@resources.each do |resource|
56
+ resource.close if resource && resource.respond_to?(:close) && !resource.closed?
57
+ end
58
+ # in case somebody spawns recursively
59
+ @@resources.clear
60
+ end
61
+
62
+ def self.alive?(pid)
63
+ begin
64
+ Process::kill 0, pid
65
+ # if the process is alive then kill won't throw an exception
66
+ true
67
+ rescue Errno::ESRCH
68
+ false
69
+ end
70
+ end
71
+
72
+ def self.kill_punks
73
+ @@punks.each do |punk|
74
+ if alive?(punk)
75
+ @@logger.info "spawn> parent(#{Process.pid}) killing child(#{punk})"
76
+ begin
77
+ Process.kill("TERM", punk)
78
+ rescue
79
+ end
80
+ end
81
+ end
82
+ @@punks = []
83
+ end
84
+ # register to kill marked children when parent exits
85
+ at_exit {kill_punks}
86
+
87
+ # Spawns a long-running section of code and returns the ID of the spawned process.
88
+ # By default the process will be a forked process. To use threading, pass
89
+ # :method => :thread or override the default behavior in the environment by setting
90
+ # 'Spawn::method :thread'.
91
+ def spawn(opts = {})
92
+ options = @@default_options.merge(opts.symbolize_keys)
93
+ # setting options[:method] will override configured value in default_options[:method]
94
+ if options[:method] == :yield
95
+ yield
96
+ elsif options[:method] == :thread
97
+ # for versions before 2.2, check for allow_concurrency
98
+ if RAILS_2_2 || ActiveRecord::Base.allow_concurrency
99
+ thread_it(options) { yield }
100
+ else
101
+ @@logger.error("spawn(:method=>:thread) only allowed when allow_concurrency=true")
102
+ raise "spawn requires config.active_record.allow_concurrency=true when used with :method=>:thread"
103
+ end
104
+ else
105
+ fork_it(options) { yield }
106
+ end
107
+ end
108
+
109
+ def wait(sids = [])
110
+ # wait for all threads and/or forks (if a single sid passed in, convert to array first)
111
+ Array(sids).each do |sid|
112
+ if sid.type == :thread
113
+ sid.handle.join()
114
+ else
115
+ begin
116
+ Process.wait(sid.handle)
117
+ rescue
118
+ # if the process is already done, ignore the error
119
+ end
120
+ end
121
+ end
122
+ # clean up connections from expired threads
123
+ ActiveRecord::Base.verify_active_connections!()
124
+ end
125
+
126
+ class SpawnId
127
+ attr_accessor :type
128
+ attr_accessor :handle
129
+ def initialize(t, h)
130
+ self.type = t
131
+ self.handle = h
132
+ end
133
+ end
134
+
135
+ protected
136
+ def fork_it(options)
137
+ # The problem with rails is that it only has one connection (per class),
138
+ # so when we fork a new process, we need to reconnect.
139
+ @@logger.debug "spawn> parent PID = #{Process.pid}"
140
+ child = fork do
141
+ begin
142
+ start = Time.now
143
+ @@logger.debug "spawn> child PID = #{Process.pid}"
144
+
145
+ # this child has no children of it's own to kill (yet)
146
+ @@punks = []
147
+
148
+ # set the nice priority if needed
149
+ Process.setpriority(Process::PRIO_PROCESS, 0, options[:nice]) if options[:nice]
150
+
151
+ # disconnect from the listening socket, et al
152
+ Spawn.close_resources
153
+ # get a new connection so the parent can keep the original one
154
+ ActiveRecord::Base.spawn_reconnect
155
+
156
+ # set the process name
157
+ $0 = options[:argv] if options[:argv]
158
+
159
+ # run the block of code that takes so long
160
+ yield
161
+
162
+ rescue => ex
163
+ @@logger.error "spawn> Exception in child[#{Process.pid}] - #{ex.class}: #{ex.message}"
164
+ ensure
165
+ begin
166
+ # to be safe, catch errors on closing the connnections too
167
+ if RAILS_2_2
168
+ ActiveRecord::Base.connection_handler.clear_all_connections!
169
+ else
170
+ ActiveRecord::Base.connection.disconnect!
171
+ ActiveRecord::Base.remove_connection
172
+ end
173
+ ensure
174
+ @@logger.info "spawn> child[#{Process.pid}] took #{Time.now - start} sec"
175
+ # ensure log is flushed since we are using exit!
176
+ @@logger.flush if @@logger.respond_to?(:flush)
177
+ # this child might also have children to kill if it called spawn
178
+ Spawn::kill_punks
179
+ # this form of exit doesn't call at_exit handlers
180
+ exit!(0)
181
+ end
182
+ end
183
+ end
184
+
185
+ # detach from child process (parent may still wait for detached process if they wish)
186
+ Process.detach(child)
187
+
188
+ # remove dead children from the target list to avoid memory leaks
189
+ @@punks.delete_if {|punk| !Spawn::alive?(punk)}
190
+
191
+ # mark this child for death when this process dies
192
+ if options[:kill]
193
+ @@punks << child
194
+ @@logger.debug "spawn> death row = #{@@punks.inspect}"
195
+ end
196
+
197
+ return SpawnId.new(:fork, child)
198
+ end
199
+
200
+ def thread_it(options)
201
+ # clean up stale connections from previous threads
202
+ ActiveRecord::Base.verify_active_connections!()
203
+ thr = Thread.new do
204
+ # run the long-running code block
205
+ yield
206
+ end
207
+ thr.priority = -options[:nice] if options[:nice]
208
+ return SpawnId.new(:thread, thr)
209
+ end
210
+
211
+ end
@@ -0,0 +1,15 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'tlconnor-spawn'
5
+ gem.version = '1.0.0'
6
+ gem.platform = Gem::Platform::RUBY
7
+ gem.authors = ['Tim Connor']
8
+ gem.email = 'tlconnor@gmail.com'
9
+ gem.summary = 'Spawn'
10
+ gem.description = gem.summary
11
+
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.require_paths = ["lib"]
15
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tlconnor-spawn
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Tim Connor
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-03-09 00:00:00 +13:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Spawn
23
+ email: tlconnor@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - CHANGELOG
33
+ - LICENSE
34
+ - README.markdown
35
+ - lib/spawn.rb
36
+ - lib/spawn/patches.rb
37
+ - lib/spawn/spawn.rb
38
+ - tlconnor-spawn.gemspec
39
+ has_rdoc: true
40
+ homepage:
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ hash: 3
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.6.2
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Spawn
73
+ test_files: []
74
+