resque-pool 0.6.0 → 0.7.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.
@@ -0,0 +1,4 @@
1
+ foo: 37
2
+ bar: 42
3
+ baz: 3
4
+ quux: 7
@@ -0,0 +1,2 @@
1
+ default: --format pretty --strict --require features --tags "not @wip and not @pending"
2
+ rake: --format progress --strict --require features --tags "not @wip and not @pending"
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec :path => ".."
@@ -0,0 +1,80 @@
1
+ PATH
2
+ remote: /home/nick/src/active/resque-pool
3
+ specs:
4
+ resque-pool (0.3.0.dev)
5
+ rake
6
+ resque (~> 1.20)
7
+ trollop (~> 1.16)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ SystemTimer (1.2.3)
13
+ aruba (0.4.11)
14
+ childprocess (>= 0.2.3)
15
+ cucumber (>= 1.1.1)
16
+ ffi (>= 1.0.11)
17
+ rspec (>= 2.7.0)
18
+ builder (3.0.0)
19
+ childprocess (0.3.2)
20
+ ffi (~> 1.0.6)
21
+ cucumber (1.1.9)
22
+ builder (>= 2.1.2)
23
+ diff-lcs (>= 1.1.2)
24
+ gherkin (~> 2.9.0)
25
+ json (>= 1.4.6)
26
+ term-ansicolor (>= 1.0.6)
27
+ diff-lcs (1.1.3)
28
+ ffi (1.0.11)
29
+ gherkin (2.9.3)
30
+ json (>= 1.4.6)
31
+ hpricot (0.8.6)
32
+ json (1.6.6)
33
+ multi_json (1.3.2)
34
+ mustache (0.99.4)
35
+ rack (1.4.1)
36
+ rack-protection (1.2.0)
37
+ rack
38
+ rake (0.9.2.2)
39
+ rdiscount (1.6.8)
40
+ redis (2.2.2)
41
+ redis-namespace (1.0.3)
42
+ redis (< 3.0.0)
43
+ resque (1.20.0)
44
+ multi_json (~> 1.0)
45
+ redis-namespace (~> 1.0.2)
46
+ sinatra (>= 0.9.2)
47
+ vegas (~> 0.1.2)
48
+ ronn (0.7.3)
49
+ hpricot (>= 0.8.2)
50
+ mustache (>= 0.7.0)
51
+ rdiscount (>= 1.5.8)
52
+ rspec (2.9.0)
53
+ rspec-core (~> 2.9.0)
54
+ rspec-expectations (~> 2.9.0)
55
+ rspec-mocks (~> 2.9.0)
56
+ rspec-core (2.9.0)
57
+ rspec-expectations (2.9.1)
58
+ diff-lcs (~> 1.1.3)
59
+ rspec-mocks (2.9.0)
60
+ sinatra (1.3.2)
61
+ rack (~> 1.3, >= 1.3.6)
62
+ rack-protection (~> 1.2)
63
+ tilt (~> 1.3, >= 1.3.3)
64
+ term-ansicolor (1.0.7)
65
+ tilt (1.3.3)
66
+ trollop (1.16.2)
67
+ vegas (0.1.11)
68
+ rack (>= 1.0.0)
69
+
70
+ PLATFORMS
71
+ ruby
72
+
73
+ DEPENDENCIES
74
+ SystemTimer
75
+ aruba (~> 0.4.11)
76
+ bundler (~> 1.0)
77
+ cucumber (~> 1.1.9)
78
+ resque-pool!
79
+ ronn
80
+ rspec (~> 2.9.0)
@@ -0,0 +1,8 @@
1
+ # If you have redis running on the standard port on localhost, then you can
2
+ # test out resque-pool in the examples directory by running:
3
+ #
4
+ # rake --trace resque:pool
5
+ #
6
+ # And then you can poke and prod the various processes with signals and edit
7
+ # the config file, etc.
8
+ require 'resque/pool/tasks'
@@ -0,0 +1,46 @@
1
+ roles = %w[solo util]
2
+ if roles.include?(node[:instance_role])
3
+ node[:applications].each do |app, data|
4
+
5
+ pidfile = "/data/#{app}/current/tmp/pids/#{app}_resque.pid"
6
+
7
+ template "/etc/monit.d/#{app}_resque.monitrc" do
8
+ owner 'root'
9
+ group 'root'
10
+ mode 0644
11
+ source "monitrc.erb"
12
+ variables({
13
+ :app_name => app,
14
+ :pidfile => pidfile,
15
+ #:max_mem => "400 MB",
16
+ })
17
+ end
18
+
19
+ template "/etc/init.d/#{app}_resque" do
20
+ owner 'root'
21
+ group 'root'
22
+ mode 0744
23
+ source "initd.erb"
24
+ variables({
25
+ :app_name => app,
26
+ :pidfile => pidfile,
27
+ })
28
+ end
29
+
30
+ execute "enable-resque" do
31
+ command "rc-update add #{app}_resque default"
32
+ action :run
33
+ not_if "rc-update show | grep -q '^ *#{app}_resque |.*default'"
34
+ end
35
+
36
+ execute "start-resque" do
37
+ command %Q{/etc/init.d/#{app}_resque start}
38
+ creates pidfile
39
+ end
40
+
41
+ execute "ensure-resque-is-setup-with-monit" do
42
+ command %Q{monit reload}
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,69 @@
1
+ #!/bin/sh -e
2
+ # Copyright (C) nicholas a. evans <nick@ekenosen.net>
3
+ # See LICENSE.txt
4
+
5
+ ### BEGIN INIT INFO
6
+ # Provides: resque-pool-<%= @app_name %>
7
+ # Required-Start: $local_fs $remote_fs $network
8
+ # Required-Stop: $local_fs $remote_fs $network
9
+ # Default-Start: 2 3 4 5
10
+ # Default-Stop: 0 1 6
11
+ # Short-Description: resque-pool init script for <%= @app_name %>
12
+ # Description: resque-pool manages the resque workers
13
+ ### END INIT INFO
14
+
15
+ # configure these values here or in /etc/default/resque-pool
16
+ # make sure your pidfile here matches your monitrc
17
+ app_name="<%= @app_name %>"
18
+ pidfile="<%= @pidfile %>"
19
+ app_dir="/data/${app_name}/current"
20
+ run_as_user="deploy"
21
+ sleep_time_during_restart=5
22
+ stop_schedule="QUIT/30/INT/10/KILL/5"
23
+ bundler="/usr/bin/bundle"
24
+ environment="production"
25
+ stdout_log="${app_dir}/log/resque-pool-${app_name}.stdout.log"
26
+ stderr_log="${app_dir}/log/resque-pool-${app_name}.stderr.log"
27
+
28
+ # override above values, and set any other env variables you need
29
+ if [ -f /etc/default/resque ] ; then
30
+ . /etc/default/resque
31
+ fi
32
+ if [ -f /etc/default/${app_name}_resque ] ; then
33
+ . /etc/default/${app_name}_resque
34
+ fi
35
+
36
+ case "$1" in
37
+ start)
38
+ # I'm assuming that you are using bundler. If you are using rip or
39
+ # something else, you'll need to change this. Remember to
40
+ # keep the double-dash; e.g.: --startas CMD -- ARGS
41
+ start-stop-daemon --start --pidfile ${pidfile} \
42
+ --chuid ${run_as_user} --chdir ${app_dir} \
43
+ --startas ${bundler} -- exec \
44
+ resque-pool -d -a ${app_name} -p ${pidfile} -E ${environment} -o ${stdout_log} -e ${stderr_log}
45
+ ;;
46
+ reload)
47
+ start-stop-daemon --stop --pidfile ${pidfile} --signal HUP
48
+ ;;
49
+ graceful-stop)
50
+ start-stop-daemon --stop --pidfile ${pidfile} --signal QUIT
51
+ ;;
52
+ quick-stop)
53
+ start-stop-daemon --stop --pidfile ${pidfile} --signal INT
54
+ ;;
55
+ stop)
56
+ start-stop-daemon --stop --pidfile ${pidfile} --retry=${stop_schedule}
57
+ ;;
58
+ restart)
59
+ $0 stop
60
+ sleep ${sleep_time_during_restart}
61
+ $0 start
62
+ ;;
63
+ *)
64
+ echo "Usage: $0 {start|stop|graceful-stop|quick-stop|restart|reload}"
65
+ exit 1
66
+ ;;
67
+ esac
68
+
69
+ # vim:ft=sh
@@ -0,0 +1,6 @@
1
+ check process <%= @app_name %>_resque
2
+ with pidfile <%= @pidfile %>
3
+ start program = "/etc/init.d/<%= @app_name %>_resque start" with timeout 90 seconds
4
+ stop program = "/etc/init.d/<%= @app_name %>_resque stop" with timeout 90 seconds
5
+ #if totalmem is greater than <%= @max_mem || "300 MB" %> for 10 cycles then restart # eating up memory?
6
+ group resque
@@ -0,0 +1,22 @@
1
+ require 'resque/pool/tasks'
2
+
3
+ # this task will get called before resque:pool:setup
4
+ # preload the rails environment in the pool master
5
+ task "resque:setup" => :environment do
6
+ # generic worker setup, e.g. Hoptoad for failed jobs
7
+ end
8
+
9
+ task "resque:pool:setup" do
10
+ # close any sockets or files in pool master
11
+ ActiveRecord::Base.connection.disconnect!
12
+
13
+ # and re-open them in the resque worker parent
14
+ Resque::Pool.after_prefork do |job|
15
+ ActiveRecord::Base.establish_connection
16
+ end
17
+
18
+ # you could also re-open them in the resque worker child, using
19
+ # Resque.after_fork, but that probably isn't necessary, and
20
+ # Resque::Pool.after_prefork should be faster, since it won't run
21
+ # for every single job.
22
+ end
@@ -0,0 +1,43 @@
1
+ rails_env = ENV['RAILS_ENV'] || 'production'
2
+ rails_root = ENV['RAILS_ROOT'] || "YOUR-APP-PATH"
3
+
4
+ God.watch do |w|
5
+ w.dir = "#{rails_root}"
6
+ w.name = "resque-pool"
7
+ w.group = 'resque'
8
+ w.interval = 30.seconds
9
+ w.env = { "RAILS_ENV" => rails_env }
10
+ w.start = "bundle exec resque-pool -d -o #{rails_root}/log/resque-pool.stdout -e #{rails_root}/log/resque-pool.stderr -p #{rails_root}/tmp/pids/resque-pool.pid"
11
+
12
+ w.pid_file = "#{rails_root}/tmp/pids/resque-pool.pid"
13
+ w.behavior(:clean_pid_file)
14
+
15
+ # determine the state on startup
16
+ w.transition(:init, { true => :up, false => :start }) do |on|
17
+ on.condition(:process_running) do |c|
18
+ c.running = true
19
+ end
20
+ end
21
+
22
+ # determine when process has finished starting
23
+ w.transition([:start, :restart], :up) do |on|
24
+ on.condition(:process_running) do |c|
25
+ c.running = true
26
+ c.interval = 5.seconds
27
+ end
28
+
29
+ # failsafe
30
+ on.condition(:tries) do |c|
31
+ c.times = 5
32
+ c.transition = :start
33
+ c.interval = 5.seconds
34
+ end
35
+ end
36
+
37
+ # start if process is not running
38
+ w.transition(:up, :start) do |on|
39
+ on.condition(:process_running) do |c|
40
+ c.running = false
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,4 @@
1
+ foo: 1
2
+ bar: 2
3
+ "foo,bar,baz": 4
4
+
@@ -0,0 +1,24 @@
1
+ # Seamless reload of resque-pool after a deploy.
2
+ # Assuming resque-pool is already running, invoke with
3
+ # `sudo initctl emit resque-pool-reload`.
4
+ description "resque-pool-reload"
5
+
6
+ start on resque-pool-reload
7
+
8
+ task
9
+
10
+ limit nofile 65536 65536
11
+
12
+ # You may need to set things like PATH here.
13
+ env HOME=/home/your_app_user
14
+ export HOME
15
+
16
+ script
17
+ source /home/your_app_user/app_env.sh
18
+ cd /your/app_root
19
+ /usr/local/bin/setuidgid your_app_user bundle exec resque-pool \
20
+ --daemon --hot-swap
21
+ # Optionally add:
22
+ # --lock /path/to/your/lock_file
23
+ # --config /path/to/resque_pool_config.yml
24
+ end script
@@ -0,0 +1,44 @@
1
+ # Manages resque-pool.
2
+ # Start the process with `initctl start resque-pool`.
3
+ description "resque-pool"
4
+
5
+ start on virtual-filesystems
6
+ stop on runlevel [06]
7
+
8
+ respawn
9
+ kill timeout 30
10
+ limit nofile 65536 65536
11
+
12
+ # You may need to set things like PATH here.
13
+ env HOME=/home/your_app_user
14
+ export HOME
15
+
16
+ # Ensure no subsequently deployed instances are running after shutdown.
17
+ post-stop script
18
+ /usr/bin/pkill -INT -f resque-pool-master
19
+ end script
20
+
21
+ # This script assumes you will deploy new application code by using
22
+ # something similar to upstart-reload.conf which runs a second copy of
23
+ # the application then shuts down the first when ready to fork. The
24
+ # --lock argument should point to a file that is accessible across
25
+ # deploys (i.e. not under a capistrano versioned path). setuidgid is
26
+ # only necessary if you are running an older version of upstart such as
27
+ # the one included with RHEL/Centos 6. In Upstart 1.4 and above you can
28
+ # use the setuid and setgid directives instead.
29
+ script
30
+ # Assuming you use environment-based configuration.
31
+ source /home/your_app_user/app_env.sh
32
+ cd /your/app_root
33
+ /usr/local/bin/setuidgid your_app_user bundle exec resque-pool \
34
+ --daemon --hot-swap
35
+ # Optionally add:
36
+ # --lock /path/to/your/lock_file \ # default: tmp/resque-pool.lock
37
+ # --config /path/to/resque_pool_config.yml # default: config/resque-pool.yml
38
+
39
+ # The above daemon will shutdown if another resque-pool is started using the
40
+ # --kill-others or --hot-swap. This line will block until all pool instances
41
+ # are terminated, ensuring that upstart doesn't try to restart our process
42
+ # unless it is actually dead.
43
+ flock -x 0 < /path/to/your/lock_file
44
+ end script
File without changes
@@ -4,7 +4,7 @@ require 'resque/worker'
4
4
  require 'resque/pool/version'
5
5
  require 'resque/pool/logging'
6
6
  require 'resque/pool/pooled_worker'
7
- require 'resque/pool/file_or_hash_loader'
7
+ require 'resque/pool/config_loaders/file_or_hash_loader'
8
8
  require 'erb'
9
9
  require 'fcntl'
10
10
  require 'yaml'
@@ -28,34 +28,49 @@ module Resque
28
28
  procline "(initialized)"
29
29
  end
30
30
 
31
- # Config: after_prefork {{{
31
+ # Config: hooks {{{
32
32
 
33
- # The `after_prefork` hooks will be run in workers if you are using the
34
- # preforking master worker to save memory. Use these hooks to reload
35
- # database connections and so forth to ensure that they're not shared
36
- # among workers. The worker instance is passed as an argument to the block.
37
- #
38
- # Call with a block to set a hook.
39
- # Call with no arguments to return all registered hooks.
40
- #
41
- def self.after_prefork(&block)
42
- @after_prefork ||= []
43
- block ? (@after_prefork << block) : @after_prefork
33
+ def self.hook(name) # :nodoc:
34
+ class_eval <<-CODE
35
+ def self.#{name}(&block)
36
+ @#{name} ||= []
37
+ block ? (@#{name} << block) : @#{name}
38
+ end
39
+
40
+ def self.#{name}=(block)
41
+ @#{name} = [block]
42
+ end
43
+
44
+ def call_#{name}!(*args)
45
+ self.class.#{name}.each do |hook|
46
+ hook.call(*args)
47
+ end
48
+ end
49
+ CODE
44
50
  end
45
51
 
46
- # Sets the after_prefork proc, clearing all pre-existing hooks.
47
- # Warning: you probably don't want to clear out the other hooks.
48
- # You can use `Resque::Pool.after_prefork << my_hook` instead.
52
+ ##
53
+ # :call-seq:
54
+ # after_prefork do |worker| ... end => add a hook
55
+ # after_prefork << hook => add a hook
49
56
  #
50
- def self.after_prefork=(after_prefork)
51
- @after_prefork = [after_prefork]
52
- end
57
+ # +after_prefork+ will run in workers before any jobs. Use these hooks e.g.
58
+ # to reload database connections to ensure that they're not shared among
59
+ # workers.
60
+ #
61
+ # :yields: worker
62
+ hook :after_prefork
53
63
 
54
- def call_after_prefork!(worker)
55
- self.class.after_prefork.each do |hook|
56
- hook.call(worker)
57
- end
58
- end
64
+ ##
65
+ # :call-seq:
66
+ # after_prefork do |worker, pid, workers| ... end => add a hook
67
+ # after_prefork << hook => add a hook
68
+ #
69
+ # The `after_spawn` hooks will run in the master after spawning a new
70
+ # worker.
71
+ #
72
+ # :yields: worker, pid, workers
73
+ hook :after_spawn
59
74
 
60
75
  # }}}
61
76
  # Config: class methods to start up the pool using the config loader {{{
@@ -73,6 +88,11 @@ module Resque
73
88
  @handle_winch = bool
74
89
  end
75
90
 
91
+ def self.kill_other_pools!
92
+ require 'resque/pool/killer'
93
+ Resque::Pool::Killer.run
94
+ end
95
+
76
96
  def self.single_process_group=(bool)
77
97
  ENV["RESQUE_SINGLE_PGRP"] = !!bool ? "YES" : "NO"
78
98
  end
@@ -99,7 +119,7 @@ module Resque
99
119
  def init_config(loader)
100
120
  case loader
101
121
  when String, Hash, nil
102
- @config_loader = FileOrHashLoader.new(loader)
122
+ @config_loader = ConfigLoaders::FileOrHashLoader.new(loader)
103
123
  else
104
124
  @config_loader = loader
105
125
  end
@@ -220,6 +240,7 @@ module Resque
220
240
 
221
241
  class << self
222
242
  attr_accessor :term_behavior
243
+ attr_accessor :kill_other_pools
223
244
  end
224
245
 
225
246
  def graceful_worker_shutdown_and_wait!(signal)
@@ -264,6 +285,7 @@ module Resque
264
285
  procline("(started)")
265
286
  log "started manager"
266
287
  report_worker_pool_pids
288
+ self.class.kill_other_pools! if self.class.kill_other_pools
267
289
  self
268
290
  end
269
291
 
@@ -396,13 +418,14 @@ module Resque
396
418
  worker.work(ENV['INTERVAL'] || DEFAULT_WORKER_INTERVAL) # interval, will block
397
419
  end
398
420
  workers[queues][pid] = worker
421
+ call_after_spawn!(worker, pid, workers)
399
422
  end
400
423
 
401
424
  def create_worker(queues)
402
425
  queues = queues.to_s.split(',')
403
426
  worker = ::Resque::Worker.new(*queues)
404
427
  worker.pool_master_pid = Process.pid
405
- worker.term_timeout = ENV['RESQUE_TERM_TIMEOUT'] || 4.0
428
+ worker.term_timeout = (ENV['RESQUE_TERM_TIMEOUT'] || 4.0).to_f
406
429
  worker.term_child = ENV['TERM_CHILD']
407
430
  if worker.respond_to?(:run_at_exit_hooks=)
408
431
  # resque doesn't support this until 1.24, but we support 1.22