resque-forker 1.3.0 → 2.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/CHANGELOG +15 -0
- data/README.rdoc +56 -6
- data/bin/resque-ctl +22 -0
- data/lib/resque/forker.rb +1 -2
- data/lib/resque/forker/version.rb +5 -0
- data/lib/resque/master.rb +222 -0
- data/resque-forker.gemspec +4 -3
- metadata +11 -8
data/CHANGELOG
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
2011-02-02 v2.0 Now, with resque-ctl
|
2
|
+
|
3
|
+
You can now run workers from the command line
|
4
|
+
|
5
|
+
$ resque-ctl -c config/resque_workers.rb
|
6
|
+
|
7
|
+
or with bundler
|
8
|
+
|
9
|
+
$ bundle exec resque-ctl -c config/resque_workers.rb
|
10
|
+
|
11
|
+
Check the README for more details and how to configure.
|
12
|
+
|
13
|
+
This awesome feature, brought to you by Todd Fisher (taf2).
|
14
|
+
|
15
|
+
|
1
16
|
2010-09-16 v1.3 Show command in Resque console, USR1 dumps to syslog
|
2
17
|
|
3
18
|
Resque console now shows forker script command (look for 'script'). This will
|
data/README.rdoc
CHANGED
@@ -16,7 +16,60 @@ application once and then forking it. Forking all these workers takes
|
|
16
16
|
milliseconds. Faster restart means faster deploy and less downtime. Yay!
|
17
17
|
|
18
18
|
|
19
|
-
==
|
19
|
+
== Configuring your Workers to use resque-ctl
|
20
|
+
|
21
|
+
Create a Ruby script that loads the applications, handles
|
22
|
+
connections, and decides what kind of workload (how many workers on which
|
23
|
+
queues) to process.
|
24
|
+
|
25
|
+
Edit this to your needs and place it in config/resque_workers.rb:
|
26
|
+
|
27
|
+
worker_processes 1 # number of worker processes to spawn
|
28
|
+
worker_queues ["*"] # listen on all worker queues
|
29
|
+
worker_timeout 30 # timeout a worker
|
30
|
+
work_interval 3 # intervals to poll
|
31
|
+
|
32
|
+
working_directory "/app/path" # where to run daemonized workers
|
33
|
+
pid "/app/path/tmp/pids/workers.pid" # master process pid
|
34
|
+
stderr_path "/app/path/log/workers.stderr.log"
|
35
|
+
stdout_path "/app/path/log/workers.stdout.log"
|
36
|
+
preload_app true
|
37
|
+
daemonize true
|
38
|
+
|
39
|
+
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true
|
40
|
+
|
41
|
+
setup do|forker|
|
42
|
+
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
|
43
|
+
|
44
|
+
if Rails.env.development?
|
45
|
+
forker.options.verbose = true
|
46
|
+
else
|
47
|
+
forker.logger = Rails.logger
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
# run in master
|
53
|
+
before_fork do
|
54
|
+
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
|
55
|
+
end
|
56
|
+
|
57
|
+
# run in worker
|
58
|
+
after_fork do
|
59
|
+
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
|
60
|
+
end
|
61
|
+
|
62
|
+
The configuration should seem very similar to how unicorn sets up it's configuration.
|
63
|
+
|
64
|
+
You can now run workers from the command line:
|
65
|
+
|
66
|
+
$ resque-ctl -c config/resque_workers.rb
|
67
|
+
|
68
|
+
or with bundler
|
69
|
+
|
70
|
+
$ bundle exec resque-ctl -c config/resque_workers.rb
|
71
|
+
|
72
|
+
== Using a script/workers control file
|
20
73
|
|
21
74
|
We're going to create a Ruby script that loads the applications, handles
|
22
75
|
connections, and decides what kind of workload (how many workers on which
|
@@ -25,21 +78,18 @@ queues) to process.
|
|
25
78
|
Edit this to your needs and place it in script/workers:
|
26
79
|
|
27
80
|
#!/usr/bin/env ruby
|
28
|
-
# If using Bundler, you might need to uncomment next two lines
|
29
|
-
#require "bundler"
|
30
|
-
#Bundler.setup
|
31
81
|
require "resque/forker"
|
32
82
|
|
33
83
|
# Load the application.
|
34
84
|
Resque.setup do |forker|
|
35
85
|
$:.unshift File.dirname(__FILE__) + "/.." # Makes 1.9.2 happy
|
36
|
-
require "config/environment"
|
86
|
+
require File.dirname(__FILE__) + "/../config/environment"
|
37
87
|
ActiveRecord::Base.connection.disconnect!
|
38
|
-
forker.options.interval = 1
|
39
88
|
if Rails.env.production?
|
40
89
|
forker.logger = Rails.logger
|
41
90
|
forker.workload = ["*"] * 4 # 4 workers on all queues
|
42
91
|
forker.user "www-data", "www-data" # don't run as root
|
92
|
+
forker.options.interval = 1
|
43
93
|
else
|
44
94
|
forker.options.verbose = true
|
45
95
|
end
|
data/bin/resque-ctl
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: binary -*-
|
3
|
+
|
4
|
+
ENV["RACK_ENV"] ||= "development"
|
5
|
+
require 'optparse'
|
6
|
+
require "resque/forker"
|
7
|
+
require "resque/master"
|
8
|
+
|
9
|
+
options = Resque::Master.optparse!
|
10
|
+
options = Resque::Master.process(options[:config]).merge(options) if options[:config]
|
11
|
+
options = Resque::Master.defaults.merge(options)
|
12
|
+
|
13
|
+
Resque::Master.setup(options)
|
14
|
+
|
15
|
+
if options[:daemon]
|
16
|
+
STDERR.puts "[Warning]: running without dropping a pid file #{Process.pid}" if options[:pidfile].nil?
|
17
|
+
STDERR.puts "[Warning]: running daemon in #{options[:runpath]}" if options[:runpath] == '/'
|
18
|
+
|
19
|
+
Resque::Master.daemonize(options)
|
20
|
+
else
|
21
|
+
Resque.fork!
|
22
|
+
end
|
data/lib/resque/forker.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "logger"
|
2
2
|
require "resque"
|
3
3
|
require "syslog"
|
4
|
+
require 'resque/forker/version'
|
4
5
|
|
5
6
|
module Resque
|
6
7
|
# Loading Rails, the application and all its dependencies takes significant time
|
@@ -63,8 +64,6 @@ module Resque
|
|
63
64
|
# respawn
|
64
65
|
class Forker
|
65
66
|
|
66
|
-
VERSION = "1.3.0"
|
67
|
-
|
68
67
|
Options = Struct.new(:verbose, :very_verbose, :interval, :terminate)
|
69
68
|
|
70
69
|
def initialize(options = nil)
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require "resque/forker"
|
3
|
+
|
4
|
+
module Resque
|
5
|
+
|
6
|
+
class Master
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
def worker_processes(count)
|
10
|
+
@options[:worker_processes] = count
|
11
|
+
end
|
12
|
+
|
13
|
+
def worker_queues(queues)
|
14
|
+
@options[:worker_queues] = queues
|
15
|
+
end
|
16
|
+
|
17
|
+
def worker_timeout(timeout)
|
18
|
+
@options[:worker_timeout] = timeout
|
19
|
+
end
|
20
|
+
|
21
|
+
def work_interval(interval)
|
22
|
+
@options[:work_interval] = interval
|
23
|
+
end
|
24
|
+
|
25
|
+
def working_directory(path)
|
26
|
+
@options[:runpath] = path
|
27
|
+
end
|
28
|
+
|
29
|
+
def pid(pidfile)
|
30
|
+
@options[:pidfile] = pidfile
|
31
|
+
end
|
32
|
+
|
33
|
+
def stderr_path(path)
|
34
|
+
@options[:stderr_path] = path
|
35
|
+
end
|
36
|
+
|
37
|
+
def stdout_path(path)
|
38
|
+
@options[:stdout_path] = path
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup(&block)
|
42
|
+
@options[:setup] = block
|
43
|
+
end
|
44
|
+
|
45
|
+
def teardown(&block)
|
46
|
+
@options[:teardown] = block
|
47
|
+
end
|
48
|
+
|
49
|
+
def before_fork(&block)
|
50
|
+
@options[:before_fork] = block
|
51
|
+
end
|
52
|
+
|
53
|
+
def after_fork(&block)
|
54
|
+
@options[:after_fork] = block
|
55
|
+
end
|
56
|
+
|
57
|
+
def preload_app(yes_no)
|
58
|
+
@options[:preload_app] = yes_no
|
59
|
+
end
|
60
|
+
|
61
|
+
def daemonize(yes_no)
|
62
|
+
@options[:daemon] = yes_no
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize(path)
|
66
|
+
@config_path = path
|
67
|
+
@options = {}
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.process(config_path)
|
71
|
+
loader = Resque::Master.new(config_path)
|
72
|
+
loader.run
|
73
|
+
loader.options
|
74
|
+
end
|
75
|
+
|
76
|
+
def run
|
77
|
+
eval(File.read(@config_path), binding)
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.setup(options)
|
81
|
+
puts "running setup with: #{options.inspect}"
|
82
|
+
|
83
|
+
Resque.setup do |forker|
|
84
|
+
puts "calling resque setup: #{options.inspect}"
|
85
|
+
if options[:preload_app]
|
86
|
+
$:.unshift options[:runpath] # Makes 1.9.2 happy
|
87
|
+
require options[:runpath] + "/config/environment"
|
88
|
+
forker.logger = Rails.logger
|
89
|
+
end
|
90
|
+
|
91
|
+
File.open(options[:pidfile],"wb") {|f| f << Process.pid }
|
92
|
+
forker.workload = options[:worker_queues] * options[:worker_processes].to_i
|
93
|
+
forker.options.interval = options[:work_interval].to_i if options.key?(:work_interval)
|
94
|
+
end
|
95
|
+
|
96
|
+
Resque.teardown do|forker|
|
97
|
+
File.unlink(options[:pidfile]) if File.exist?(options[:pidfile])
|
98
|
+
end
|
99
|
+
|
100
|
+
Resque.before_first_fork do
|
101
|
+
options[:before_first_fork].call if options[:before_first_fork].is_a?(Proc)
|
102
|
+
end
|
103
|
+
|
104
|
+
Resque.before_fork do
|
105
|
+
options[:before_fork].call if options[:before_fork].is_a?(Proc)
|
106
|
+
end
|
107
|
+
|
108
|
+
Resque.after_fork do
|
109
|
+
options[:after_fork].call if options[:after_fork].is_a?(Proc)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.daemonize(options)
|
114
|
+
$pidfile = options[:pidfile]
|
115
|
+
rd, wr = IO.pipe
|
116
|
+
|
117
|
+
stdout = options[:stdout_path] || "/dev/null"
|
118
|
+
stderr = options[:stderr_path] || "/dev/null"
|
119
|
+
|
120
|
+
# wait for child process to start running before exiting parent process
|
121
|
+
fork do
|
122
|
+
rd.close
|
123
|
+
Process.setsid
|
124
|
+
fork do
|
125
|
+
begin
|
126
|
+
wr.write "Prepare to fork: #{options.inspect}, stdout: #{stdout.inspect}, stderr: #{stderr.inspect}, stdin: /dev/null"
|
127
|
+
Process.setsid
|
128
|
+
Dir.chdir(options[:runpath])
|
129
|
+
File.umask 0000
|
130
|
+
STDIN.reopen "/dev/null"
|
131
|
+
STDOUT.reopen stdout, "a"
|
132
|
+
STDERR.reopen stderr, "a"
|
133
|
+
|
134
|
+
wr.flush
|
135
|
+
wr.close # signal to our parent we're up and running, this lets the parent exit
|
136
|
+
|
137
|
+
Resque.fork! # fork to startup the workers
|
138
|
+
rescue => e
|
139
|
+
if wr.closed?
|
140
|
+
STDERR.puts "#{e.message} #{e.backtrace.join("\n")}"
|
141
|
+
else
|
142
|
+
wr.write e.message
|
143
|
+
wr.write e.backtrace.join("\n")
|
144
|
+
wr.write "\n"
|
145
|
+
wr.write "ERROR!"
|
146
|
+
wr.flush
|
147
|
+
wr.close
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
wr.close
|
152
|
+
end
|
153
|
+
|
154
|
+
wr.close
|
155
|
+
output = rd.read
|
156
|
+
puts output
|
157
|
+
rd.close
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.optparse!
|
162
|
+
options = {}
|
163
|
+
|
164
|
+
optparse = OptionParser.new do|opts|
|
165
|
+
# Set a banner, displayed at the top
|
166
|
+
# of the help screen.
|
167
|
+
opts.banner = "Usage: optparse1.rb [options] file1 file2 ..."
|
168
|
+
|
169
|
+
opts.on( '-d', '--daemon', 'Run the master process as daemon' ) do
|
170
|
+
options[:daemon] = true
|
171
|
+
end
|
172
|
+
|
173
|
+
opts.on( '-p', '--pid FILE', 'Write pid file to FILE' ) do|file|
|
174
|
+
options[:pidfile] = file
|
175
|
+
end
|
176
|
+
|
177
|
+
opts.on( '-r', '--run PATH', 'Where to run the forked daemon' ) do|file|
|
178
|
+
options[:runpath] = file
|
179
|
+
end
|
180
|
+
|
181
|
+
opts.on( '-e', '--stderr PATH', 'Where to send stderr output' ) do|file|
|
182
|
+
options[:stderr_path] = file
|
183
|
+
end
|
184
|
+
|
185
|
+
opts.on( '-o', '--stdout PATH', 'Where to send stdout output' ) do|file|
|
186
|
+
options[:stdout_path] = file
|
187
|
+
end
|
188
|
+
|
189
|
+
opts.on( '-c', '--config PATH', 'Path to a configuration file to load' ) do|file|
|
190
|
+
options[:config] = file
|
191
|
+
end
|
192
|
+
|
193
|
+
opts.on( '-l', '--logfile FILE', 'Write log to FILE' ) do|file|
|
194
|
+
options[:logfile] = file
|
195
|
+
end
|
196
|
+
|
197
|
+
# This displays the help screen, all programs are
|
198
|
+
# assumed to have this option.
|
199
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
200
|
+
puts opts
|
201
|
+
exit
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
optparse.parse!
|
206
|
+
options
|
207
|
+
end
|
208
|
+
|
209
|
+
def self.defaults
|
210
|
+
{
|
211
|
+
:config => nil,
|
212
|
+
:logfile => nil,
|
213
|
+
:stderr_path => "/dev/null",
|
214
|
+
:stdout_path => "/dev/null",
|
215
|
+
:runpath => "/",
|
216
|
+
:pidfile => nil,
|
217
|
+
:daemon => false
|
218
|
+
}
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
end
|
data/resque-forker.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
require "resque/forker"
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__) + "/lib")
|
2
|
+
require "resque/forker/version"
|
3
3
|
|
4
4
|
Gem::Specification.new do |spec|
|
5
5
|
spec.name = "resque-forker"
|
@@ -10,8 +10,9 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.summary = "Super awesome forking action for Resque workers"
|
11
11
|
spec.description = "Use the power of forking to run multiple Resque workers."
|
12
12
|
spec.post_install_message = ""
|
13
|
+
spec.executables = %w(resque-ctl)
|
13
14
|
|
14
|
-
spec.files = Dir["{lib,script,etc}/**/*", "CHANGELOG", "MIT-LICENSE", "README.rdoc", "Rakefile", "*.gemspec"]
|
15
|
+
spec.files = Dir["{lib,script,etc,bin}/**/*", "CHANGELOG", "MIT-LICENSE", "README.rdoc", "Rakefile", "*.gemspec"]
|
15
16
|
|
16
17
|
spec.has_rdoc = true
|
17
18
|
spec.extra_rdoc_files = "README.rdoc", "CHANGELOG"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-forker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
|
-
-
|
8
|
-
- 3
|
7
|
+
- 2
|
9
8
|
- 0
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Assaf Arkin
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-02-03 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -34,8 +34,8 @@ dependencies:
|
|
34
34
|
version_requirements: *id001
|
35
35
|
description: Use the power of forking to run multiple Resque workers.
|
36
36
|
email: assaf@labnotes.org
|
37
|
-
executables:
|
38
|
-
|
37
|
+
executables:
|
38
|
+
- resque-ctl
|
39
39
|
extensions: []
|
40
40
|
|
41
41
|
extra_rdoc_files:
|
@@ -43,10 +43,13 @@ extra_rdoc_files:
|
|
43
43
|
- CHANGELOG
|
44
44
|
files:
|
45
45
|
- lib/resque/capistrano.rb
|
46
|
+
- lib/resque/forker/version.rb
|
46
47
|
- lib/resque/forker.rb
|
48
|
+
- lib/resque/master.rb
|
47
49
|
- script/trigger
|
48
50
|
- script/workers
|
49
51
|
- etc/init/workers.conf
|
52
|
+
- bin/resque-ctl
|
50
53
|
- CHANGELOG
|
51
54
|
- MIT-LICENSE
|
52
55
|
- README.rdoc
|
@@ -59,7 +62,7 @@ licenses: []
|
|
59
62
|
post_install_message: ""
|
60
63
|
rdoc_options:
|
61
64
|
- --title
|
62
|
-
- Resque Forker
|
65
|
+
- Resque Forker 2.0.0
|
63
66
|
- --main
|
64
67
|
- README.rdoc
|
65
68
|
- --webcvs
|