resque-pool 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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