resque-forker 1.3.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
- == Creating the script
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,5 @@
1
+ module Resque
2
+ class Forker
3
+ VERSION = "2.0.0"
4
+ end
5
+ end
@@ -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
@@ -1,5 +1,5 @@
1
- $: << File.dirname(__FILE__) + "/lib"
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: 27
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
- - 1
8
- - 3
7
+ - 2
9
8
  - 0
10
- version: 1.3.0
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: 2010-09-16 00:00:00 -07:00
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 1.3.0
65
+ - Resque Forker 2.0.0
63
66
  - --main
64
67
  - README.rdoc
65
68
  - --webcvs