resque-forker 1.0.beta
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/CHANGELOG +2 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +163 -0
- data/Rakefile +22 -0
- data/lib/resque/forker.rb +232 -0
- data/resque-forker.gemspec +19 -0
- data/script/workers +18 -0
- metadata +96 -0
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Copyright (c) 2010 Flowtown, Inc.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
= Resque::Forker
|
|
2
|
+
|
|
3
|
+
Super awesome forking action for Resque workers.
|
|
4
|
+
|
|
5
|
+
== Forking Workers
|
|
6
|
+
|
|
7
|
+
If you're like us, you have a sizeable application with many models, libraries
|
|
8
|
+
and dependencies that are shared between the front-facing UI and the back-end
|
|
9
|
+
processing. And like us, you're Resque worker are loading the entire application
|
|
10
|
+
each time the fire up.
|
|
11
|
+
|
|
12
|
+
If you're running 8 workers that can be quite the CPU-churning delay loading
|
|
13
|
+
them all up. Exactly the problem we're going to solve by starting the
|
|
14
|
+
application once and then forking it. Forking all these workers takes
|
|
15
|
+
milliseconds. Faster restart means faster deploy and less downtime. Yay!
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
== Creating the script
|
|
19
|
+
|
|
20
|
+
We're going to create a Ruby script that loads the applications, handles
|
|
21
|
+
connections, and decides what kind of workload (how many workers on which
|
|
22
|
+
queues) to process.
|
|
23
|
+
|
|
24
|
+
Edit this to your needs and place it in script/workers:
|
|
25
|
+
|
|
26
|
+
#!/usr/bin/env ruby
|
|
27
|
+
require "resque/forker"
|
|
28
|
+
|
|
29
|
+
# Load the application.
|
|
30
|
+
Resque.setup do |forker|
|
|
31
|
+
require File.dirname(__FILE__) + "/../config/environment"
|
|
32
|
+
ActiveRecord::Base.connection.disconnect!
|
|
33
|
+
if Rails.env.production?
|
|
34
|
+
forker.logger = Rails.logger
|
|
35
|
+
forker.workload = ["*"] * 4 # 4 workers on all queues
|
|
36
|
+
forker.user "www-data", "www-data" # don't run as root
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
# Stuff to do after forking a worker.
|
|
40
|
+
Resque.after_fork do
|
|
41
|
+
ActiveRecord::Base.establish_connection
|
|
42
|
+
end
|
|
43
|
+
Resque.fork!
|
|
44
|
+
|
|
45
|
+
You can now run workers from the command line:
|
|
46
|
+
|
|
47
|
+
$ ruby script/workers
|
|
48
|
+
|
|
49
|
+
In development mode you will get one worker that outputs to the console. In
|
|
50
|
+
production you get four workers that log messages to the Rails logger and run
|
|
51
|
+
under the www-data account (never run as root).
|
|
52
|
+
|
|
53
|
+
Worker processes can't share connections with each other, so we're closing the
|
|
54
|
+
database connection from the master process and then establishing new connection
|
|
55
|
+
for each individual worker. You'll have to do the same with other libraries that
|
|
56
|
+
maintain open connections (MongoMapper, Vanity, etc)
|
|
57
|
+
|
|
58
|
+
You tell Resque::Forker what workload to process using an array of queue lists.
|
|
59
|
+
Each array element represents one worker, so 4 elements would start up four
|
|
60
|
+
workers. The element's value tell the worker which queues to process. For
|
|
61
|
+
example, if you want four workers processing the import queue, and two of these
|
|
62
|
+
workers also processing the export queue:
|
|
63
|
+
|
|
64
|
+
forker.workload = ["import", "import,export"] * 2
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
== Controlling the Workers
|
|
68
|
+
|
|
69
|
+
You can use these signals to control individual workers, or send them to the
|
|
70
|
+
master process, which will propagate them to all workers:
|
|
71
|
+
|
|
72
|
+
kill -QUIT -- Quit gracefully
|
|
73
|
+
kill -TERM -- Terminate immediately
|
|
74
|
+
kill -USR1 -- Stop any ongoing job
|
|
75
|
+
kill -USR2 -- Suspend worker
|
|
76
|
+
kill -CONT -- Resume suspended worker
|
|
77
|
+
|
|
78
|
+
After deploying you want to stop all workers, reload the master process (and
|
|
79
|
+
the application and its configuration) and have all workers restarted. Simply
|
|
80
|
+
send it the HUP signal. That easy.
|
|
81
|
+
|
|
82
|
+
You probably want to suspend/resume (USR2/CONT signals) if you're doing any
|
|
83
|
+
maintenance work that may disrupt the workers, like rake db:migrate. Of course
|
|
84
|
+
you can stop/start the master process, but what would be the fun of that.
|
|
85
|
+
|
|
86
|
+
Of course, you want the workers to start after reboot and each way to control
|
|
87
|
+
them. Read on how to use Resque::Forker with Upstart.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
== Using Upstart and Capistrano
|
|
91
|
+
|
|
92
|
+
If you're running a recent release of Ubuntu, you can get Upstart to manage your
|
|
93
|
+
workers.
|
|
94
|
+
|
|
95
|
+
Edit this to your needs and place it in /etc/init/workers:
|
|
96
|
+
|
|
97
|
+
start on runlevel [2345]
|
|
98
|
+
stop on runlevel [06]
|
|
99
|
+
chdir /var/www/myapp/current
|
|
100
|
+
env RAILS_ENV=production
|
|
101
|
+
exec script/workers
|
|
102
|
+
respawn
|
|
103
|
+
|
|
104
|
+
After reading this, Upstart to make sure your workers are always up and running.
|
|
105
|
+
It's awesome like that.
|
|
106
|
+
|
|
107
|
+
To start, stop, check status and reload:
|
|
108
|
+
|
|
109
|
+
$ start workers
|
|
110
|
+
$ stop workers
|
|
111
|
+
$ status workers
|
|
112
|
+
$ reload workers
|
|
113
|
+
|
|
114
|
+
You need to be root to start/stop the workers. However, if you change ownership
|
|
115
|
+
of the workers (see fork.user above) you can reload them as that user. You can
|
|
116
|
+
do something like this in your Capfile:
|
|
117
|
+
|
|
118
|
+
namespace :workers do
|
|
119
|
+
task :pause do
|
|
120
|
+
run "status workers | cut -d ' ' -f 4 | xargs kill -USR2"
|
|
121
|
+
end
|
|
122
|
+
task :resume do
|
|
123
|
+
run "status workers | cut -d ' ' -f 4 | xargs kill -CONT"
|
|
124
|
+
end
|
|
125
|
+
task :reload do
|
|
126
|
+
run "reload workers"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
after "deploy:update_code", "workers:reload"
|
|
130
|
+
|
|
131
|
+
Because of the way Upstart works, there is no need for PID file or running as
|
|
132
|
+
daemon. Yay for sane process supervisors! When you reload workers,
|
|
133
|
+
Resque::Forker reloads itself (and the application) while keeping the same PID.
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
== Troubleshooting
|
|
137
|
+
|
|
138
|
+
If you're using Bundler, you might need to run the script using:
|
|
139
|
+
|
|
140
|
+
exec bundle exec script/workers
|
|
141
|
+
|
|
142
|
+
If you're using RVM and Bundler, you might need to create a wrapper and use it:
|
|
143
|
+
|
|
144
|
+
exec run_bundle script/workers
|
|
145
|
+
|
|
146
|
+
The point is, when the script starts it will expect both resque and
|
|
147
|
+
resque-forker must be available for loading (that typically means GEMPATH).
|
|
148
|
+
Depending on your setup, they may be loaded by Bundler, available in the RVM
|
|
149
|
+
gemset, installed as system gems, etc.
|
|
150
|
+
|
|
151
|
+
If you're hitting a wall, remember that any settings and aliases that you have
|
|
152
|
+
in .bashrc (RVM, for example, or the path to bundle) are not sourced by Upstart,
|
|
153
|
+
so commands that "just work" when you run from the console will fail.
|
|
154
|
+
|
|
155
|
+
What you can do to troubleshoot this situation is run as root in a new shell
|
|
156
|
+
that doesn't have your regular account settings:
|
|
157
|
+
|
|
158
|
+
$ env -i sudo /bin/bash --norc --noprofile
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
== Credits
|
|
162
|
+
|
|
163
|
+
Copyright (c) 2010 Flowtown, Inc.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
spec = Gem::Specification.load(File.expand_path("resque-forker.gemspec", File.dirname(__FILE__)))
|
|
2
|
+
|
|
3
|
+
desc "Build the Gem"
|
|
4
|
+
task :build do
|
|
5
|
+
sh "gem build #{spec.name}.gemspec"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
desc "Install #{spec.name} locally"
|
|
9
|
+
task :install=>:build do
|
|
10
|
+
sudo = "sudo" unless File.writable?( Gem::ConfigMap[:bindir])
|
|
11
|
+
sh "#{sudo} gem install #{spec.name}-#{spec.version}.gem"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
desc "Push new release to gemcutter and git tag"
|
|
15
|
+
task :push=>["build"] do
|
|
16
|
+
sh "git push"
|
|
17
|
+
puts "Tagging version #{spec.version} .."
|
|
18
|
+
sh "git tag v#{spec.version}"
|
|
19
|
+
sh "git push --tag"
|
|
20
|
+
puts "Building and pushing gem .."
|
|
21
|
+
sh "gem push #{spec.name}-#{spec.version}.gem"
|
|
22
|
+
end
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
require "logger"
|
|
2
|
+
require "resque"
|
|
3
|
+
|
|
4
|
+
module Resque
|
|
5
|
+
# Loading Rails, the application and all its dependencies takes significant time
|
|
6
|
+
# and eats up memory. We keep startup time manageable by loading the application
|
|
7
|
+
# once and forking the worker processes. When using REE, this will also keep
|
|
8
|
+
# memory usage low. Note that we can't reuse connections and file handles in
|
|
9
|
+
# child processes, so no saving on opening database connections, etc.
|
|
10
|
+
#
|
|
11
|
+
# To use this library, wrap your setup and teardown blocks:
|
|
12
|
+
# Resque.setup do |forker|
|
|
13
|
+
# require File.dirname(__FILE__) + "/../config/environment"
|
|
14
|
+
# ActiveRecord::Base.connection.disconnect!
|
|
15
|
+
# forker.logger = Rails.logger
|
|
16
|
+
# forker.user "nobody", "nobody"
|
|
17
|
+
# end
|
|
18
|
+
# Resque.after_fork do
|
|
19
|
+
# ActiveRecord::Base.establish_connection
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# Most libraries cannot share connections between child processes, you want to
|
|
23
|
+
# close these in the parent process (during setup) and reopen connections for
|
|
24
|
+
# each worker when it needs it to process a job (during after_work). This
|
|
25
|
+
# example shows how to do that for ActiveRecord, you will need to do the same
|
|
26
|
+
# for other libraries, e.g. MongoMapper, Vanity.
|
|
27
|
+
#
|
|
28
|
+
# All the forking action is handled by a single call:
|
|
29
|
+
# # Three workers, processing all queues
|
|
30
|
+
# Resque.fork! ["*"] * 3
|
|
31
|
+
#
|
|
32
|
+
# The workload is specified as an array of lists of queues, that way you can
|
|
33
|
+
# decide how many workers to fork (length of the array) and give each worker
|
|
34
|
+
# different set of queues to work with. For example, to have four workers
|
|
35
|
+
# processing import queue, and only two of these also processing export queue:
|
|
36
|
+
#
|
|
37
|
+
# Resque.fork! ["import,export", "import"] * 2
|
|
38
|
+
#
|
|
39
|
+
# Once the process is up and running, you control it by sending signals:
|
|
40
|
+
# - kill -QUIT -- Quit gracefully
|
|
41
|
+
# - kill -TERM -- Terminate immediately
|
|
42
|
+
# - kill -USR2 -- Suspend all workers (e.g when running rake db:migrate)
|
|
43
|
+
# - kill -CONT -- Resume suspended workers
|
|
44
|
+
# - kill -HUP -- Shutdown and restart
|
|
45
|
+
#
|
|
46
|
+
# The HUP signal will wait for all existing jobs to complete, run the teardown
|
|
47
|
+
# block, and reload the script with the same environment and arguments. It will
|
|
48
|
+
# reload the application, the libraries, and of course any configuration changes
|
|
49
|
+
# in this script (e.g. changes to the workload).
|
|
50
|
+
#
|
|
51
|
+
# The reloaded process keeps the same PID so you can use it with upstart:
|
|
52
|
+
# reload workers
|
|
53
|
+
# The upstart script could look something like this:
|
|
54
|
+
# start on runlevel [2345]
|
|
55
|
+
# stop on runlevel [06]
|
|
56
|
+
# chdir /var/app/current
|
|
57
|
+
# env RAILS_ENV=production
|
|
58
|
+
# exec script/workers
|
|
59
|
+
# respawn
|
|
60
|
+
class Forker
|
|
61
|
+
def initialize(options = nil)
|
|
62
|
+
@options = options || {}
|
|
63
|
+
@logger = @options[:logger] || Logger.new($stderr)
|
|
64
|
+
@workload = ["*"]
|
|
65
|
+
@children = []
|
|
66
|
+
begin
|
|
67
|
+
require "system_timer"
|
|
68
|
+
@timeout = SystemTimer.method(:timeout_after)
|
|
69
|
+
rescue NameError, LoadError
|
|
70
|
+
require "timeout"
|
|
71
|
+
@timeout = method(:timeout)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Workload is an array of queue sets, one entry per workers (so four entries
|
|
76
|
+
# if you want four workers). Each entry is comma-separated queue names.
|
|
77
|
+
attr_accessor :workload
|
|
78
|
+
|
|
79
|
+
# Defaults to stderr, but you may want to point this at Rails logger.
|
|
80
|
+
attr_accessor :logger
|
|
81
|
+
|
|
82
|
+
# Run and never return.
|
|
83
|
+
def run
|
|
84
|
+
@logger.info "** Running as #{Process.pid}"
|
|
85
|
+
setup_signals
|
|
86
|
+
if setup = Resque.setup
|
|
87
|
+
@logger.info "** Loading application ..."
|
|
88
|
+
setup.call self
|
|
89
|
+
end
|
|
90
|
+
reap_children
|
|
91
|
+
@logger.info "** Forking workers"
|
|
92
|
+
enable_gc_optimizations
|
|
93
|
+
# Serious forking action.
|
|
94
|
+
@workload.each do |queues|
|
|
95
|
+
@children << fork { run_worker queues }
|
|
96
|
+
end
|
|
97
|
+
rescue
|
|
98
|
+
@logger.error "** Failed to load application: #{$!.message}"
|
|
99
|
+
@logger.error $!.backtrace.join("\n")
|
|
100
|
+
ensure
|
|
101
|
+
# Sleep forever.
|
|
102
|
+
sleep 5 while true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Change ownership of this process.
|
|
106
|
+
def user(user, group)
|
|
107
|
+
uid = Etc.getpwnam(user).uid
|
|
108
|
+
gid = Etc.getgrnam(group).gid
|
|
109
|
+
if Process.euid != uid || Process.egid != gid
|
|
110
|
+
Process.initgroups user, gid
|
|
111
|
+
Process::GID.change_privilege gid
|
|
112
|
+
Process::UID.change_privilege uid
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
protected
|
|
117
|
+
|
|
118
|
+
# Setup signal handlers.
|
|
119
|
+
def setup_signals
|
|
120
|
+
# Stop gracefully
|
|
121
|
+
trap :QUIT do
|
|
122
|
+
stop
|
|
123
|
+
exit
|
|
124
|
+
end
|
|
125
|
+
# Pause/continue processing
|
|
126
|
+
trap(:USR1) { Process.kill :USR1, *@children }
|
|
127
|
+
trap(:USR2) { Process.kill :USR2, *@children }
|
|
128
|
+
trap(:CONT) { Process.kill :CONT, *@children }
|
|
129
|
+
# Reincarnate. Stop children, and reload binary (application and all)
|
|
130
|
+
# while keeping same PID.
|
|
131
|
+
trap :HUP do
|
|
132
|
+
@logger.info "** Reincarnating ..."
|
|
133
|
+
stop
|
|
134
|
+
exec $0, *ARGV
|
|
135
|
+
end
|
|
136
|
+
# Terminate quickly
|
|
137
|
+
trap(:TERM) { shutdown! }
|
|
138
|
+
trap(:INT) { shutdown! }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Enables GC Optimizations if you're running REE.
|
|
142
|
+
# http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
|
|
143
|
+
def enable_gc_optimizations
|
|
144
|
+
if GC.respond_to?(:copy_on_write_friendly=)
|
|
145
|
+
GC.copy_on_write_friendly = true
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Run and never return.
|
|
150
|
+
def run_worker(queues)
|
|
151
|
+
worker = Resque::Worker.new(*queues.split(","))
|
|
152
|
+
worker.verbose = $VERBOSE
|
|
153
|
+
worker.very_verbose = $DEBUG
|
|
154
|
+
worker.work(@options[:interval] || 5) # interval, will block
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Stop child processes and run any teardown action.
|
|
158
|
+
def stop(gracefully = true)
|
|
159
|
+
@logger.info "** Quitting ..."
|
|
160
|
+
@children.each do |pid|
|
|
161
|
+
begin
|
|
162
|
+
Process.kill gracefully ? :QUIT : :TERM, pid
|
|
163
|
+
sleep 0.1
|
|
164
|
+
rescue Errno::ESRCH
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
reap_children
|
|
168
|
+
if teardown = Resque.teardown
|
|
169
|
+
@timeout.call @options[:terminate] || 5 do
|
|
170
|
+
begin
|
|
171
|
+
teardown.call self
|
|
172
|
+
rescue Exception
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
@logger.info "** Good night"
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Eat up zombies.
|
|
180
|
+
def reap_children
|
|
181
|
+
loop do
|
|
182
|
+
wpid, status = Process.waitpid2(0, Process::WNOHANG)
|
|
183
|
+
wpid or break
|
|
184
|
+
end
|
|
185
|
+
@children.clear
|
|
186
|
+
rescue Errno::ECHILD
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# When stop is not good enough.
|
|
190
|
+
def shutdown!
|
|
191
|
+
@logger.info "** Terminating"
|
|
192
|
+
stop false
|
|
193
|
+
exit!
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# Specify what needs to be done to setup the application. This is the place
|
|
200
|
+
# to load Rails or do anything expensive. For example:
|
|
201
|
+
# Resque.setup do
|
|
202
|
+
# require File.dirname(__FILE__) + "/../config/environment"
|
|
203
|
+
# ActiveRecord.disconnect
|
|
204
|
+
# end
|
|
205
|
+
def setup(&block)
|
|
206
|
+
block ? (@setup = block) : @setup
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Do this before exiting or before reloading.
|
|
210
|
+
def teardown(&block)
|
|
211
|
+
block ? (@teardown = block) : @teardown
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Forks workers to take care of the workload.
|
|
215
|
+
#
|
|
216
|
+
# The workload is an array of queue names, one entry for each worker. For
|
|
217
|
+
# example, if you want to run four workers processing all queues.
|
|
218
|
+
# Resque.fork! ["*"] * 4
|
|
219
|
+
# If you want four workers, all of which will be processing imports, but
|
|
220
|
+
# only two processing exports:
|
|
221
|
+
# Resque.fork! ["import", "import,export"] * 2
|
|
222
|
+
#
|
|
223
|
+
# Options are:
|
|
224
|
+
# - :logger -- Which Logger to use (default logger to stdout)
|
|
225
|
+
# - :interval -- Processing interval (default to 5 seconds)
|
|
226
|
+
# - :terminate -- Timeout running teardown block (default to 5 seconds)
|
|
227
|
+
def fork!(workload = nil, options = nil)
|
|
228
|
+
forker = Resque::Forker.new(options)
|
|
229
|
+
forker.workload = workload if workload
|
|
230
|
+
forker.run
|
|
231
|
+
end
|
|
232
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Gem::Specification.new do |spec|
|
|
2
|
+
spec.name = "resque-forker"
|
|
3
|
+
spec.version = "1.0.beta"
|
|
4
|
+
spec.author = "Assaf Arkin"
|
|
5
|
+
spec.email = "assaf@labnotes.org"
|
|
6
|
+
spec.homepage = "http://github.com/assaf/resque-forker"
|
|
7
|
+
spec.summary = "Super awesome forking action for Resque workers"
|
|
8
|
+
spec.post_install_message = ""
|
|
9
|
+
|
|
10
|
+
spec.files = Dir["{lib,script}/**/*", "CHANGELOG", "MIT-LICENSE", "README.rdoc", "Rakefile", "resque-forker.gemspec"]
|
|
11
|
+
|
|
12
|
+
spec.has_rdoc = true
|
|
13
|
+
spec.extra_rdoc_files = "README.rdoc", "CHANGELOG"
|
|
14
|
+
spec.rdoc_options = "--title", "Resque Forker #{spec.version}", "--main", "README.rdoc",
|
|
15
|
+
"--webcvs", "http://github.com/assaf/#{spec.name}"
|
|
16
|
+
|
|
17
|
+
spec.required_ruby_version = '>= 1.8.7'
|
|
18
|
+
spec.add_dependency "resque"
|
|
19
|
+
end
|
data/script/workers
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require "resque/forker"
|
|
3
|
+
|
|
4
|
+
# Load the application.
|
|
5
|
+
Resque.setup do |forker|
|
|
6
|
+
require File.dirname(__FILE__) + "/../config/environment"
|
|
7
|
+
ActiveRecord::Base.connection.disconnect!
|
|
8
|
+
if Rails.env.production?
|
|
9
|
+
forker.logger = Rails.logger
|
|
10
|
+
forker.workload = ["*"] * 4 # 4 workers on all queues
|
|
11
|
+
forker.user "www-data", "www-data" # don't run as root
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
# Stuff to do after forking a worker.
|
|
15
|
+
Resque.after_fork do
|
|
16
|
+
ActiveRecord::Base.establish_connection
|
|
17
|
+
end
|
|
18
|
+
Resque.fork!
|
metadata
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: resque-forker
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 31098137
|
|
5
|
+
prerelease: true
|
|
6
|
+
segments:
|
|
7
|
+
- 1
|
|
8
|
+
- 0
|
|
9
|
+
- beta
|
|
10
|
+
version: 1.0.beta
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Assaf Arkin
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2010-07-30 00:00:00 -07:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies:
|
|
21
|
+
- !ruby/object:Gem::Dependency
|
|
22
|
+
name: resque
|
|
23
|
+
prerelease: false
|
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
hash: 3
|
|
30
|
+
segments:
|
|
31
|
+
- 0
|
|
32
|
+
version: "0"
|
|
33
|
+
type: :runtime
|
|
34
|
+
version_requirements: *id001
|
|
35
|
+
description:
|
|
36
|
+
email: assaf@labnotes.org
|
|
37
|
+
executables: []
|
|
38
|
+
|
|
39
|
+
extensions: []
|
|
40
|
+
|
|
41
|
+
extra_rdoc_files:
|
|
42
|
+
- README.rdoc
|
|
43
|
+
- CHANGELOG
|
|
44
|
+
files:
|
|
45
|
+
- lib/resque/forker.rb
|
|
46
|
+
- script/workers
|
|
47
|
+
- CHANGELOG
|
|
48
|
+
- MIT-LICENSE
|
|
49
|
+
- README.rdoc
|
|
50
|
+
- Rakefile
|
|
51
|
+
- resque-forker.gemspec
|
|
52
|
+
has_rdoc: true
|
|
53
|
+
homepage: http://github.com/assaf/resque-forker
|
|
54
|
+
licenses: []
|
|
55
|
+
|
|
56
|
+
post_install_message: ""
|
|
57
|
+
rdoc_options:
|
|
58
|
+
- --title
|
|
59
|
+
- Resque Forker 1.0.beta
|
|
60
|
+
- --main
|
|
61
|
+
- README.rdoc
|
|
62
|
+
- --webcvs
|
|
63
|
+
- http://github.com/assaf/resque-forker
|
|
64
|
+
require_paths:
|
|
65
|
+
- lib
|
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
67
|
+
none: false
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
hash: 57
|
|
72
|
+
segments:
|
|
73
|
+
- 1
|
|
74
|
+
- 8
|
|
75
|
+
- 7
|
|
76
|
+
version: 1.8.7
|
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
|
+
none: false
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
hash: 25
|
|
83
|
+
segments:
|
|
84
|
+
- 1
|
|
85
|
+
- 3
|
|
86
|
+
- 1
|
|
87
|
+
version: 1.3.1
|
|
88
|
+
requirements: []
|
|
89
|
+
|
|
90
|
+
rubyforge_project:
|
|
91
|
+
rubygems_version: 1.3.7
|
|
92
|
+
signing_key:
|
|
93
|
+
specification_version: 3
|
|
94
|
+
summary: Super awesome forking action for Resque workers
|
|
95
|
+
test_files: []
|
|
96
|
+
|