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 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