resque-pool 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog.md CHANGED
@@ -1,4 +1,19 @@
1
- ## 0.1.0 (unreleased)
1
+ ## unreleased
2
+
3
+ * new feature: sending `HUP` to pool manager will reload the logfiles and
4
+ gracefully restart all workers.
5
+ * enhancement: logging now includes timestamp, process "name" (worker or
6
+ manager), and PID.
7
+ * enhancement: can be used with no config file or empty config file (not all
8
+ *that* useful, but it's better than unceromoniously dieing!)
9
+ * bugfix: pidfile will be cleaned up on startup, e.g. if old process was
10
+ kill-9'd (Jason Haruska)
11
+ * bugfix: TERM/INT are no longer ignored when HUP is waiting on children
12
+ * bugfix: `resque-pool -c config.yml` command line option was broken
13
+ * development: simple cucumber features for core functionality.
14
+ * upstream: depends on resque ~> 1.13
15
+
16
+ ## 0.1.0 (2011-01-18)
2
17
 
3
18
  * new feature: `resque-pool` command line interface
4
19
  * this replaces need for a special startup script.
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  Resque Pool
2
2
  ===========
3
3
 
4
- Resque pool is a simple library for managing a pool of resque workers. Given a
5
- a config file, it manages your workers for you, starting up the appropriate
6
- number of workers for each.
4
+ Resque pool is a simple library for managing a pool of
5
+ [resque](http://github.com/defunkt/resque) workers. Given a a config file, it
6
+ manages your workers for you, starting up the appropriate number of workers for
7
+ each worker type.
7
8
 
8
9
  Benefits
9
10
  ---------
@@ -16,17 +17,18 @@ Benefits
16
17
  when you are managing many workers.
17
18
  * Faster startup - when you start many workers at once, they would normally
18
19
  compete for CPU as they load their environments. Resque-pool can load the
19
- environment once and almost instantaneously fork all of the workers.
20
+ environment once and fork all of the workers almost instantly.
20
21
 
21
22
  How to use
22
23
  -----------
23
24
 
24
25
  ### YAML file config
25
26
 
26
- Create a `config/resque-pool.yml` with your worker counts. The YAML file
27
- supports both using root level defaults as well as environment specific
28
- overrides (`RACK_ENV`, `RAILS_ENV`, and `RESQUE_ENV` environment variables can
29
- be used to determine environment). For example in `config/resque-pool.yml`:
27
+ Create a `config/resque-pool.yml` (or `resque-pool.yml`) with your worker
28
+ counts. The YAML file supports both using root level defaults as well as
29
+ environment specific overrides (`RACK_ENV`, `RAILS_ENV`, and `RESQUE_ENV`
30
+ environment variables can be used to determine environment). For example in
31
+ `config/resque-pool.yml`:
30
32
 
31
33
  foo: 1
32
34
  bar: 2
@@ -37,10 +39,11 @@ be used to determine environment). For example in `config/resque-pool.yml`:
37
39
 
38
40
  ### Rake task config
39
41
 
40
- Require the rake tasks (`resque/pool/tasks`) in your rake file, configure
41
- Resque as necessary, and configure `Resque::Pool` to disconnect all open
42
- sockets in the pool manager and reconnect in the workers. For example, with
43
- rails you should put the following into `lib/tasks/resque.rake`:
42
+ Require the rake tasks (`resque/pool/tasks`) in your `Rakefile`, load your
43
+ application environment, configure Resque as necessary, and configure
44
+ `resque:pool:setup` to disconnect all open files and sockets in the pool
45
+ manager and reconnect in the workers. For example, with rails you should put
46
+ the following into `lib/tasks/resque.rake`:
44
47
 
45
48
  require 'resque/pool/tasks'
46
49
  # this task will get called before resque:pool:setup
@@ -61,7 +64,7 @@ rails you should put the following into `lib/tasks/resque.rake`:
61
64
 
62
65
  Then you can start the queues via:
63
66
 
64
- resque-pool --environment production
67
+ resque-pool --daemon --environment production
65
68
 
66
69
  This will start up seven worker processes, one exclusively for the foo queue,
67
70
  two exclusively for the bar queue, and four workers looking at all queues in
@@ -80,20 +83,19 @@ three levels: a single pool manager, many worker parents, and one worker child
80
83
  per worker (when the actual job is being processed). For example, `ps -ef f |
81
84
  grep [r]esque` (in Linux) might return something like the following:
82
85
 
83
- rails 13858 1 0 13:44 ? S 0:02 resque-pool-manager: managing [13867, 13875, 13871, 13872, 13868, 13870, 13876]
84
- rails 13867 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for foo
85
- rails 13868 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for bar
86
- rails 13870 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for bar
87
- rails 13871 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for foo,bar,baz
88
- rails 13872 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Forked 7481 at 1280343254
89
- rails 7481 13872 0 14:54 ? S 0:00 \_ resque-1.9.9: Processing foo since 1280343254
90
- rails 13875 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for foo,bar,baz
91
- rails 13876 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Forked 7485 at 1280343255
92
- rails 7485 13876 0 14:54 ? S 0:00 \_ resque-1.9.9: Processing bar since 1280343254
93
-
94
- You can also run resque-pool as a daemon via `--daemon`. It will default to
95
- placing the pidfile and logfiles in the rails default locations, which you may
96
- want to configure. The `RAILS_ENV` can be specified via `--environment`. See
86
+ resque 13858 1 0 13:44 ? S 0:02 resque-pool-manager: managing [13867, 13875, 13871, 13872, 13868, 13870, 13876]
87
+ resque 13867 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for foo
88
+ resque 13868 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for bar
89
+ resque 13870 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for bar
90
+ resque 13871 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for foo,bar,baz
91
+ resque 13872 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Forked 7481 at 1280343254
92
+ resque 7481 13872 0 14:54 ? S 0:00 \_ resque-1.9.9: Processing foo since 1280343254
93
+ resque 13875 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Waiting for foo,bar,baz
94
+ resque 13876 13858 0 13:44 ? S 0:00 \_ resque-1.9.9: Forked 7485 at 1280343255
95
+ resque 7485 13876 0 14:54 ? S 0:00 \_ resque-1.9.9: Processing bar since 1280343254
96
+
97
+ Running as a daemon will default to placing the pidfile and logfiles in the
98
+ conventional rails locations, although you can configure that. See
97
99
  `resque-pool --help` for more options.
98
100
 
99
101
  SIGNALS
@@ -101,24 +103,23 @@ SIGNALS
101
103
 
102
104
  The pool manager responds to the following signals:
103
105
 
104
- * `HUP` - reload the config file, e.g. to change the number of workers per queue list
106
+ * `HUP` - reload the config file, reload logfiles, restart all workers.
105
107
  * `QUIT` - send `QUIT` to each worker parent and shutdown the manager after all workers are done.
106
108
  * `INT` - send `QUIT` to each worker parent and immediately shutdown manager
107
109
  * `TERM` - send `TERM` to each worker parent and immediately shutdown manager
108
110
  * `WINCH` - send `QUIT` to each worker, but keep manager running (send `HUP` to reload config and restart workers)
109
- * `USR1`/`USR2`/`CONT` - send the signal on to all worker parents (see Resque docs).
111
+ * `USR1`/`USR2`/`CONT` - pass the signal on to all worker parents (see Resque docs).
110
112
 
111
- After a `HUP`, workers that are no longer needed will be gracefully shutdown
112
- via `QUIT`.
113
+ Use `HUP` to help logrotate run smoothly and to change the number of workers
114
+ per worker type.
113
115
 
114
116
  Other Features
115
117
  --------------
116
118
 
117
- An example chef recipe is provided (it should work at Engine Yard as is; just
118
- provide a `/data/#{app_name}/shared/config/resque-pool.yml` on your utility
119
- servers). Even if you don't use chef, you can still use the example init.d
120
- script and monitrc (erb templates) provided in
121
- `examples/chef_cookbook/templates/default`.
119
+ An example chef cookbook is provided (and should Just Work at Engine Yard as
120
+ is; just provide a `/data/#{app_name}/shared/config/resque-pool.yml` on your
121
+ utility instances). Even if you don't use chef you can use the example init.d
122
+ and monitrc erb templates in `examples/chef_cookbook/templates/default`.
122
123
 
123
124
  You can also start a pool manager via `rake resque:pool` or from a plain old
124
125
  ruby script by calling `Resque::Pool.run`.
@@ -132,20 +133,7 @@ with the `--config` command line option.
132
133
  TODO
133
134
  -----
134
135
 
135
- * web interface for adding and removing workers (etc)
136
- * config file split by hostname
137
- * rename to `resque-squad`?
138
- * cmd line option for non-rake loading
139
- * cmd line option for preloading ruby file
140
- * provide Unix style log formatter (compatible with $stdout/$stderr)
141
- * recover gracefully from a malformed config file (on startup and HUP)
142
- * change procline for malformed config file, graceful shutdown... and other states?
143
- * figure out a good automated way to test this (cucumber or rspec?)
144
- * clean up the code (I stole most of it from unicorn, and it's still a bit
145
- bastardized); excessive use of vim foldmarkers are a code smell!
146
- * rdoc
147
- * integrate with or incorporate resque-batchworker features? (v2.0)
148
- * integrate with resque-scheduler? (v2.0)
136
+ See [the TODO list](https://github.com/nevans/resque-pool/issues) at github issues.
149
137
 
150
138
  Contributors
151
139
  -------------
@@ -154,3 +142,4 @@ Contributors
154
142
  * Stephen Celis (increased gemspec sanity)
155
143
  * Vincent Agnello, Robert Kamunyori, Paul Kauders; for pairing with me at
156
144
  B'more on Rails Open Source Hack Nights. :)
145
+
data/Rakefile CHANGED
@@ -1,3 +1,17 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ # for loading the example config file in config/resque-pool.yml
3
5
  require 'resque/pool/tasks'
6
+
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.rspec_opts = ["-c", "-f progress"]
10
+ end
11
+
12
+ require 'cucumber/rake/task'
13
+ Cucumber::Rake::Task.new(:features) do |c|
14
+ c.profile = "rake"
15
+ end
16
+
17
+ task :default => [:spec, :features]
@@ -0,0 +1,3 @@
1
+ default: --format pretty --strict --require features --tags ~@wip --tags ~@pending
2
+ rake: --format progress --strict --require features --tags ~@wip --tags ~@pending
3
+
data/examples/Gemfile ADDED
@@ -0,0 +1 @@
1
+ gemspec :path => ".."
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: /home/nick/src/active/resque-pool
3
+ specs:
4
+ resque-pool (0.1.0.dev)
5
+ rake
6
+ resque (~> 1.13)
7
+ trollop (~> 1.16)
8
+
9
+ GEM
10
+ specs:
11
+ SystemTimer (1.2.2)
12
+ aruba (0.3.2)
13
+ childprocess (~> 0.1.6)
14
+ cucumber (~> 0.10.0)
15
+ rspec (~> 2.3.0)
16
+ builder (3.0.0)
17
+ childprocess (0.1.7)
18
+ ffi (~> 0.6.3)
19
+ cucumber (0.10.0)
20
+ builder (>= 2.1.2)
21
+ diff-lcs (~> 1.1.2)
22
+ gherkin (~> 2.3.2)
23
+ json (~> 1.4.6)
24
+ term-ansicolor (~> 1.0.5)
25
+ diff-lcs (1.1.2)
26
+ ffi (0.6.3)
27
+ rake (>= 0.8.7)
28
+ gherkin (2.3.3)
29
+ json (~> 1.4.6)
30
+ json (1.4.6)
31
+ rack (1.2.1)
32
+ rake (0.8.7)
33
+ redis (2.1.1)
34
+ redis-namespace (0.10.0)
35
+ redis (< 3.0.0)
36
+ resque (1.13.0)
37
+ json (~> 1.4.6)
38
+ redis-namespace (>= 0.10.0)
39
+ sinatra (>= 0.9.2)
40
+ vegas (~> 0.1.2)
41
+ rspec (2.3.0)
42
+ rspec-core (~> 2.3.0)
43
+ rspec-expectations (~> 2.3.0)
44
+ rspec-mocks (~> 2.3.0)
45
+ rspec-core (2.3.1)
46
+ rspec-expectations (2.3.0)
47
+ diff-lcs (~> 1.1.2)
48
+ rspec-mocks (2.3.0)
49
+ sinatra (1.1.3)
50
+ rack (~> 1.1)
51
+ tilt (>= 1.2.2, < 2.0)
52
+ term-ansicolor (1.0.5)
53
+ tilt (1.2.2)
54
+ trollop (1.16.2)
55
+ vegas (0.1.8)
56
+ rack (>= 1.0.0)
57
+
58
+ PLATFORMS
59
+ ruby
60
+
61
+ DEPENDENCIES
62
+ SystemTimer
63
+ aruba (~> 0.3.2)
64
+ bundler (~> 1.0)
65
+ cucumber (~> 0.10.0)
66
+ resque-pool!
67
+ rspec (~> 2.3.0)
@@ -30,7 +30,7 @@ if roles.include?(node[:instance_role])
30
30
  execute "enable-resque" do
31
31
  command "rc-update add #{app}_resque default"
32
32
  action :run
33
- not_if "rc-update show | grep -q '^ *#{app}_resque |.*default"
33
+ not_if "rc-update show | grep -q '^ *#{app}_resque |.*default'"
34
34
  end
35
35
 
36
36
  execute "start-resque" do
@@ -0,0 +1,53 @@
1
+ resque-pool-manager[15490]: Reopened logfile: log/resque-pool.stdout.log
2
+ resque-pool-manager[15490]: trying to reopen a log... File
3
+ resque-pool-manager[15490]: orig_st: #<File::Stat dev=0x804, ino=3409002, mode=0100644, nlink=1, uid=1000, gid=1000, rdev=0x0, size=1063, blksize=4096, blocks=8, atime=Wed Feb 23 12:20:58 -0500 2011, mtime=Tue Mar 15 21:33:44 -0400 2011, ctime=Tue Mar 15 21:33:44 -0400 2011>
4
+ resque-pool-manager[15490]: cur_stat: #<File::Stat dev=0x804, ino=3409002, mode=0100644, nlink=1, uid=1000, gid=1000, rdev=0x0, size=1063, blksize=4096, blocks=8, atime=Wed Feb 23 12:20:58 -0500 2011, mtime=Tue Mar 15 21:33:44 -0400 2011, ctime=Tue Mar 15 21:33:44 -0400 2011>
5
+ resque-pool-manager[15490]: Reopen logs: close old children which have old logfiles open
6
+ resque-pool-manager[15490]: Reopen logs: new children will inherit new logfiles
7
+ resque-pool-manager[15490]: Reaped resque worker[16074] (status: 0) queues: bar
8
+ resque-pool-manager[15490]: Reaped resque worker[16076] (status: 0) queues: foo
9
+ resque-pool-worker[16638]: Starting worker arrakis:16638:bar
10
+ resque-pool-worker[16640]: Starting worker arrakis:16640:foo
11
+ resque-pool-manager[15490]: Reaped resque worker[16083] (status: 0) queues: bar
12
+ resque-pool-manager[15490]: Reaped resque worker[16073] (status: 0) queues: foo,bar,baz
13
+ resque-pool-worker[16650]: Starting worker arrakis:16650:bar
14
+ resque-pool-worker[16652]: Starting worker arrakis:16652:foo,bar,baz
15
+ resque-pool-manager[15490]: Reaped resque worker[16078] (status: 0) queues: foo,bar,baz
16
+ resque-pool-worker[16659]: Starting worker arrakis:16659:foo,bar,baz
17
+ resque-pool-manager[15490]: Reaped resque worker[16084] (status: 0) queues: foo,bar,baz
18
+ resque-pool-manager[15490]: Reaped resque worker[16086] (status: 0) queues: foo,bar,baz
19
+ resque-pool-worker[16669]: Starting worker arrakis:16669:foo,bar,baz
20
+ resque-pool-worker[16664]: Starting worker arrakis:16664:foo,bar,baz
21
+ resque-pool-manager[15490]: TERM: immediate shutdown (and immediate worker shutdown)
22
+ resque-pool-manager[15490]: manager finished
23
+ resque-pool-manager[24768]: Resque Pool running in development environment
24
+ (in /home/nick/src/active/resque-pool/examples)
25
+ resque-pool-manager[24768]: started manager
26
+ resque-pool-manager[24768]: Pool contains worker PIDs: [24790, 24788, 24789, 24786, 24787, 24794, 24793]
27
+ resque-pool-worker[24787]: Starting worker arrakis:24787:foo,bar,baz
28
+ resque-pool-worker[24788]: Starting worker arrakis:24788:foo,bar,baz
29
+ resque-pool-worker[24786]: Starting worker arrakis:24786:foo,bar,baz
30
+ resque-pool-worker[24789]: Starting worker arrakis:24789:foo,bar,baz
31
+ resque-pool-worker[24794]: Starting worker arrakis:24794:bar
32
+ resque-pool-worker[24793]: Starting worker arrakis:24793:bar
33
+ resque-pool-worker[24790]: Starting worker arrakis:24790:foo
34
+ resque-pool-manager[24768]: HUP: reload config file and reload logfiles
35
+ resque-pool-manager[24768]: Flushing logs
36
+ resque-pool-manager[24768]: HUP: close old children which have old logfiles open
37
+ resque-pool-manager[24768]: HUP: new children will inherit new logfiles
38
+ resque-pool-manager[24768]: Reaped resque worker[24787] (status: 0) queues: foo,bar,baz
39
+ resque-pool-manager[24768]: Reaped resque worker[24794] (status: 0) queues: bar
40
+ resque-pool-manager[24768]: Reaped resque worker[24786] (status: 0) queues: foo,bar,baz
41
+ resque-pool-worker[25311]: Starting worker arrakis:25311:foo,bar,baz
42
+ resque-pool-worker[25312]: Starting worker arrakis:25312:bar
43
+ resque-pool-worker[25315]: Starting worker arrakis:25315:foo,bar,baz
44
+ resque-pool-manager[24768]: Reaped resque worker[24790] (status: 0) queues: foo
45
+ resque-pool-manager[24768]: Reaped resque worker[24788] (status: 0) queues: foo,bar,baz
46
+ resque-pool-manager[24768]: Reaped resque worker[24789] (status: 0) queues: foo,bar,baz
47
+ resque-pool-manager[24768]: Reaped resque worker[24793] (status: 0) queues: bar
48
+ resque-pool-worker[25326]: Starting worker arrakis:25326:foo
49
+ resque-pool-worker[25327]: Starting worker arrakis:25327:foo,bar,baz
50
+ resque-pool-worker[25328]: Starting worker arrakis:25328:foo,bar,baz
51
+ resque-pool-worker[25330]: Starting worker arrakis:25330:bar
52
+ resque-pool-manager[24768]: HUP: reload config file and reload logfiles
53
+ resque-pool-manager[24768]: Flushing logs
@@ -0,0 +1,68 @@
1
+ Feature: Basic resque-pool daemon configuration and operation
2
+ To easily manage a pool of resque workers, resque-pool provides a daemon with
3
+ simple configuration. Static configuration is handled in the
4
+ config/config.yml file and dynamic configuration is handled in the Rakefile.
5
+
6
+ Background:
7
+ Given a file named "Rakefile" with:
8
+ """
9
+ require 'resque/pool/tasks'
10
+ """
11
+
12
+ Scenario: no config file
13
+ When I run the pool manager as "resque-pool"
14
+ Then the pool manager should report that it has started up
15
+ And the pool manager should report that the pool is empty
16
+ And the pool manager should have no child processes
17
+ When I send the pool manager the "QUIT" signal
18
+ Then the pool manager should finish
19
+ And the pool manager should report that it is finished
20
+
21
+ @slow_exit
22
+ Scenario: basic config file
23
+ Given a file named "config/resque-pool.yml" with:
24
+ """
25
+ foo: 1
26
+ bar: 2
27
+ "bar,baz": 3
28
+ """
29
+ When I run the pool manager as "resque-pool"
30
+ Then the pool manager should report that it has started up
31
+ And the pool manager should report that 6 workers are in the pool
32
+ And the pool manager should have 1 "foo" worker child processes
33
+ And the pool manager should have 2 "bar" worker child processes
34
+ And the pool manager should have 3 "bar,baz" worker child processes
35
+ When I send the pool manager the "QUIT" signal
36
+ Then the resque workers should all shutdown
37
+ And the pool manager should finish
38
+ And the pool manager should report that a "foo" worker has been reaped
39
+ And the pool manager should report that a "bar" worker has been reaped
40
+ And the pool manager should report that a "bar,baz" worker has been reaped
41
+ And the pool manager should report that it is finished
42
+
43
+ Scenario: daemonized
44
+ Given a directory named "log"
45
+ And a directory named "tmp/pids"
46
+ And a file named "config/resque-pool.yml" with:
47
+ """
48
+ foo: 2
49
+ bar: 4
50
+ "baz,quux": 4
51
+ """
52
+ When I run the pool manager as "resque-pool -d"
53
+ Then the pool manager should record its pid in "tmp/pids/resque-pool.pid"
54
+ And the pool manager should daemonize
55
+ And a file named "log/resque-pool.stdout.log" should exist
56
+ And a file named "log/resque-pool.stderr.log" should exist
57
+ And the pool manager should log that it has started up
58
+ And the pool manager should log that 10 workers are in the pool
59
+ And the pool manager should have 2 "foo" worker child processes
60
+ And the pool manager should have 4 "bar" worker child processes
61
+ And the pool manager should have 4 "baz,quux" worker child processes
62
+ When I send the pool manager the "QUIT" signal
63
+ Then the resque workers should all shutdown
64
+ And the pool manager daemon should finish
65
+ And the pool manager should log that a "foo" worker has been reaped
66
+ And the pool manager should log that a "bar" worker has been reaped
67
+ And the pool manager should log that a "baz,quux" worker has been reaped
68
+ And the pool manager should log that it is finished
@@ -0,0 +1,29 @@
1
+ # syntactic sugar, and separate ivar. daemons aren't interactive
2
+ When /^I run "([^"]*)" in the background$/ do |cmd|
3
+ run_background(unescape(cmd))
4
+ end
5
+
6
+ Then /^the (output|logfiles) should contain the following lines \(with interpolated \$PID\):$/ do |output_logfiles, partial_output|
7
+ interpolate_background_pid(partial_output).split("\n").each do |line|
8
+ output_or_log(output_logfiles).should include(line)
9
+ end
10
+ end
11
+
12
+ When /^I send "([^"]*)" the "([^"]*)" signal$/ do |cmd, signal|
13
+ send_signal(cmd, signal)
14
+ end
15
+
16
+ Then /^the "([^"]*)" process should finish$/ do |cmd|
17
+ # doesn't actually stop... just polls for exit
18
+ processes[cmd].stop
19
+ end
20
+
21
+ Before("@slow_exit") do
22
+ @aruba_timeout_seconds = 10
23
+ end
24
+
25
+ After do
26
+ kill_all_processes!
27
+ # now kill the daemon!
28
+ `pkill -9 -f resque-pool`
29
+ end
@@ -0,0 +1,147 @@
1
+ def process_should_exist(pid)
2
+ lambda { Process.kill(0, pid) }.should_not raise_error(Errno::ESRCH)
3
+ end
4
+
5
+ def process_should_not_exist(pid)
6
+ lambda { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
7
+ end
8
+
9
+ def grab_worker_pids(count, str)
10
+ announce "TODO: check output_or_log for #{count} worker started messages"
11
+ pid_regex = (1..count).map { '(\d+)' }.join ', '
12
+ full_regex = /resque-pool-manager\[\d+\]: Pool contains worker PIDs: \[#{pid_regex}\]/m
13
+ str.should =~ full_regex
14
+ @worker_pids = full_regex.match(str).captures.map {|pid| pid.to_i }
15
+ end
16
+
17
+ def output_or_logfiles_string(report_log)
18
+ case report_log
19
+ when "report", "output"
20
+ "output"
21
+ when "log", "logfiles"
22
+ "logfiles"
23
+ else
24
+ raise ArgumentError
25
+ end
26
+ end
27
+
28
+ def output_or_log(report_log)
29
+ case report_log
30
+ when "report", "output"
31
+ all_output
32
+ when "log", "logfiles"
33
+ in_current_dir do
34
+ File.read("log/resque-pool.stdout.log") << File.read("log/resque-pool.stderr.log")
35
+ end
36
+ else
37
+ raise ArgumentError
38
+ end
39
+ end
40
+
41
+ def children_of(ppid)
42
+ ps = `ps -eo ppid,pid,cmd | grep '^ *#{ppid} '`
43
+ ps.split(/\s*\n/).map do |line|
44
+ _, pid, cmd = line.strip.split(/\s+/, 3)
45
+ [pid, cmd]
46
+ end
47
+ end
48
+
49
+ When /^I run the pool manager as "([^"]*)"$/ do |cmd|
50
+ @pool_manager_process = run_background(unescape(cmd))
51
+ end
52
+
53
+ When /^I send the pool manager the "([^"]*)" signal$/ do |signal|
54
+ Process.kill signal, background_pid
55
+ output_logfiles = @pid_from_pidfile ? "logfiles" : "output"
56
+ case signal
57
+ when "QUIT"
58
+ keep_trying do
59
+ Then "the #{output_logfiles} should contain the following lines (with interpolated $PID):", <<-EOF
60
+ resque-pool-manager[$PID]: QUIT: graceful shutdown, waiting for children
61
+ EOF
62
+ end
63
+ else
64
+ raise ArgumentError
65
+ end
66
+ end
67
+
68
+ Then /^the pool manager should record its pid in "([^"]*)"$/ do |pidfile|
69
+ in_current_dir do
70
+ keep_trying do
71
+ File.should be_file(pidfile)
72
+ @pid_from_pidfile = File.read(pidfile).to_i
73
+ @pid_from_pidfile.should_not == 0
74
+ process_should_exist(@pid_from_pidfile)
75
+ end
76
+ end
77
+ end
78
+
79
+ Then /^the pool manager should daemonize$/ do
80
+ @pool_manager_process.stop
81
+ end
82
+
83
+ Then /^the pool manager daemon should finish$/ do
84
+ keep_trying do
85
+ process_should_not_exist(@pid_from_pidfile)
86
+ end
87
+ end
88
+
89
+ # nomenclature: "report" => output to stdout/stderr
90
+ # "log" => output to default logfile
91
+
92
+ Then /^the pool manager should (report|log) that it has started up$/ do |report_log|
93
+ keep_trying do
94
+ Then "the #{output_or_logfiles_string(report_log)} should contain the following lines (with interpolated $PID):", <<-EOF
95
+ resque-pool-manager[$PID]: Resque Pool running in development environment
96
+ resque-pool-manager[$PID]: started manager
97
+ EOF
98
+ end
99
+ end
100
+
101
+ Then /^the pool manager should (report|log) that the pool is empty$/ do |report_log|
102
+ Then "the #{output_or_logfiles_string(report_log)} should contain the following lines (with interpolated $PID):", <<-EOF
103
+ resque-pool-manager[$PID]: Pool is empty
104
+ EOF
105
+ end
106
+
107
+ Then /^the pool manager should (report|log) that (\d+) workers are in the pool$/ do |report_log, count|
108
+ grab_worker_pids Integer(count), output_or_log(report_log)
109
+ end
110
+
111
+ Then /^the resque workers should all shutdown$/ do
112
+ @worker_pids.each do |pid|
113
+ keep_trying do
114
+ process_should_not_exist(pid)
115
+ end
116
+ end
117
+ end
118
+
119
+ Then "the pool manager should have no child processes" do
120
+ children_of(background_pid).should have(:no).keys
121
+ end
122
+
123
+ Then /^the pool manager should have (\d+) "([^"]*)" worker child processes$/ do |count, queues|
124
+ children_of(background_pid).select do |pid, cmd|
125
+ cmd =~ /^resque-\d+.\d+.\d+: Waiting for #{queues}$/
126
+ end.should have(Integer(count)).members
127
+ end
128
+
129
+ Then "the pool manager should finish" do
130
+ # assuming there will not be multiple processes running
131
+ processes.each { |cmd, p| p.stop }
132
+ end
133
+
134
+ Then /^the pool manager should (report|log) that it is finished$/ do |report_log|
135
+ Then "the #{output_or_logfiles_string(report_log)} should contain the following lines (with interpolated $PID):", <<-EOF
136
+ resque-pool-manager[$PID]: manager finished
137
+ EOF
138
+ end
139
+
140
+ Then /^the pool manager should (report|log) that a "([^"]*)" worker has been reaped$/ do |report_log, worker_type|
141
+ And 'the '+ output_or_logfiles_string(report_log) +' should match /Reaped resque worker\[\d+\] \(status: 0\) queues: '+ worker_type + '/'
142
+ end
143
+
144
+ Then /^the logfiles should match \/([^\/]*)\/$/ do |partial_output|
145
+ output_or_log("log").should =~ /#{partial_output}/
146
+ end
147
+
@@ -0,0 +1,60 @@
1
+ require 'aruba/api'
2
+ require 'aruba/process'
3
+
4
+ module Aruba
5
+
6
+ module Api
7
+
8
+ # this is a horrible hack, to make sure that it's done what it needs to do
9
+ # before we do our next step
10
+ def keep_trying(timeout=10, tries=0)
11
+ announce "Try: #{tries}" if @announce_env
12
+ yield
13
+ rescue RSpec::Expectations::ExpectationNotMetError
14
+ if tries < timeout
15
+ sleep 1
16
+ tries += 1
17
+ retry
18
+ else
19
+ raise
20
+ end
21
+ end
22
+
23
+ def run_background(cmd)
24
+ @background = run(cmd)
25
+ end
26
+
27
+ def send_signal(cmd, signal)
28
+ announce_or_puts "$ kill -#{signal} #{processes[cmd].pid}" if @announce_env
29
+ processes[cmd].send_signal signal
30
+ end
31
+
32
+ def background_pid
33
+ @pid_from_pidfile || @background.pid
34
+ end
35
+
36
+ def interpolate_background_pid(string)
37
+ interpolated = string.gsub('$PID', background_pid.to_s)
38
+ announce_or_puts interpolated if @announce_env
39
+ interpolated
40
+ end
41
+
42
+ def kill_all_processes!
43
+ stop_processes!
44
+ rescue
45
+ processes.each {|cmd,process| send_signal(cmd, 'KILL') }
46
+ raise
47
+ end
48
+
49
+ end
50
+
51
+ class Process
52
+ def pid
53
+ @process.pid
54
+ end
55
+ def send_signal signal
56
+ @process.send :send_signal, signal
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1 @@
1
+ require 'aruba/cucumber'
@@ -4,12 +4,13 @@ require 'resque/pool'
4
4
  module Resque
5
5
  class Pool
6
6
  module CLI
7
+ extend Logging
7
8
  extend self
8
9
 
9
10
  def run
10
11
  opts = parse_options
11
12
  daemonize if opts[:daemon]
12
- pidfile opts[:pidfile]
13
+ manage_pidfile opts[:pidfile]
13
14
  redirect opts
14
15
  setup_environment opts
15
16
  start_pool
@@ -28,12 +29,12 @@ Usage:
28
29
  resque-pool [options]
29
30
  where [options] are:
30
31
  EOS
31
- opt :config, "Alternate path to config file", :short => "-c"
32
- opt :daemon, "Run as a background daemon", :default => false, :short => "-d"
33
- opt :stdout, "Redirect stdout to logfile", :type => String, :short => '-o'
34
- opt :stderr, "Redirect stderr to logfile", :type => String, :short => '-e'
32
+ opt :config, "Alternate path to config file", :type => String, :short => "-c"
33
+ opt :daemon, "Run as a background daemon", :default => false, :short => "-d"
34
+ opt :stdout, "Redirect stdout to logfile", :type => String, :short => '-o'
35
+ opt :stderr, "Redirect stderr to logfile", :type => String, :short => '-e'
35
36
  opt :nosync, "Don't sync logfiles on every write"
36
- opt :pidfile, "PID file location", :type => String, :short => "-p"
37
+ opt :pidfile, "PID file location", :type => String, :short => "-p"
37
38
  opt :environment, "Set RAILS_ENV/RACK_ENV/RESQUE_ENV", :type => String, :short => "-E"
38
39
  end
39
40
  if opts[:daemon]
@@ -52,33 +53,52 @@ where [options] are:
52
53
  exit unless pid.nil?
53
54
  end
54
55
 
55
- def pidfile(pidfile)
56
+ def manage_pidfile(pidfile)
57
+ return unless pidfile
56
58
  pid = Process.pid
57
- if pidfile
58
- if File.exist? pidfile
59
- raise "Pidfile already exists at #{pidfile}. Check to make sure process is not already running."
59
+ if File.exist? pidfile
60
+ if process_still_running? pidfile
61
+ raise "Pidfile already exists at #{pidfile} and process is still running."
62
+ else
63
+ File.delete pidfile
60
64
  end
61
- File.open pidfile, "w" do |f|
62
- f.write pid
63
- end
64
- at_exit do
65
- if Process.pid == pid
66
- File.delete pidfile
67
- end
65
+ end
66
+ File.open pidfile, "w" do |f|
67
+ f.write pid
68
+ end
69
+ at_exit do
70
+ if Process.pid == pid
71
+ File.delete pidfile
68
72
  end
69
73
  end
70
74
  end
71
75
 
76
+ def process_still_running?(pidfile)
77
+ old_pid = open(pidfile).read.strip.to_i
78
+ Process.kill 0, old_pid
79
+ true
80
+ rescue Errno::ESRCH
81
+ false
82
+ rescue Errno::EPERM
83
+ true
84
+ rescue ::Exception
85
+ $stderr.puts "While checking if PID #{old_pid} is running, unexpected #{e.class}: #{e}"
86
+ true
87
+ end
88
+
72
89
  def redirect(opts)
73
90
  $stdin.reopen '/dev/null' if opts[:daemon]
74
- $stdout.reopen opts[:stdout], "a" if opts[:stdout] && !opts[:stdout].empty?
75
- $stderr.reopen opts[:stderr], "a" if opts[:stderr] && !opts[:stderr].empty?
91
+ # need to reopen as File, or else Resque::Pool::Logging.reopen_logs! won't work
92
+ out = File.new(opts[:stdout], "a") if opts[:stdout] && !opts[:stdout].empty?
93
+ err = File.new(opts[:stderr], "a") if opts[:stderr] && !opts[:stderr].empty?
94
+ $stdout.reopen out if out
95
+ $stderr.reopen err if err
76
96
  $stdout.sync = $stderr.sync = true unless opts[:nosync]
77
97
  end
78
98
 
79
99
  def setup_environment(opts)
80
100
  ENV["RACK_ENV"] = ENV["RAILS_ENV"] = ENV["RESQUE_ENV"] = opts[:environment] if opts[:environment]
81
- puts "Resque Pool running in #{ENV["RAILS_ENV"] || "development"} environment."
101
+ log "Resque Pool running in #{ENV["RAILS_ENV"] || "development"} environment"
82
102
  ENV["RESQUE_POOL_CONFIG"] = opts[:config] if opts[:config]
83
103
  end
84
104
 
@@ -1,6 +1,38 @@
1
1
  module Resque
2
2
  class Pool
3
3
  module Logging
4
+ extend self
5
+
6
+ # more than a little bit complicated...
7
+ # copied this from Unicorn.
8
+ def self.reopen_logs!
9
+ log "Flushing logs"
10
+ [$stdout, $stderr].each do |fd|
11
+ if fd.instance_of? File
12
+ # skip if the file is the exact same inode and device
13
+ orig_st = fd.stat
14
+ begin
15
+ cur_st = File.stat(fd.path)
16
+ next if orig_st.ino == cur_st.ino && orig_st.dev == cur_st.dev
17
+ rescue Errno::ENOENT
18
+ end
19
+ # match up the encoding
20
+ open_arg = 'a'
21
+ if fd.respond_to?(:external_encoding) && enc = fd.external_encoding
22
+ open_arg << ":#{enc.to_s}"
23
+ enc = fd.internal_encoding and open_arg << ":#{enc.to_s}"
24
+ end
25
+ # match up buffering (does reopen reset this?)
26
+ sync = fd.sync
27
+ # sync to disk
28
+ fd.fsync
29
+ # reopen, and set ruby buffering appropriately
30
+ fd.reopen fd.path, open_arg
31
+ fd.sync = sync
32
+ log "Reopened logfile: #{fd.path}"
33
+ end
34
+ end
35
+ end
4
36
 
5
37
  # Given a string, sets the procline ($0)
6
38
  # Procline is always in the format of:
@@ -11,7 +43,14 @@ module Resque
11
43
 
12
44
  # TODO: make this use an actual logger
13
45
  def log(message)
14
- puts message
46
+ puts "resque-pool-manager[#{Process.pid}]: #{message}"
47
+ #$stdout.fsync
48
+ end
49
+
50
+ # TODO: make this use an actual logger
51
+ def log_worker(message)
52
+ puts "resque-pool-worker[#{Process.pid}]: #{message}"
53
+ #$stdout.fsync
15
54
  end
16
55
 
17
56
  end
@@ -4,11 +4,11 @@ require 'resque/pool'
4
4
 
5
5
  namespace :resque do
6
6
 
7
- desc "resque worker config (not pool related). e.g. hoptoad"
7
+ # resque worker config (not pool related). e.g. hoptoad, rails environment
8
8
  task :setup
9
9
 
10
10
  namespace :pool do
11
- "resque pool config. e.g. after_prefork connection handling"
11
+ # resque pool config. e.g. after_prefork connection handling
12
12
  task :setup
13
13
  end
14
14
 
@@ -1,5 +1,5 @@
1
1
  module Resque
2
2
  class Pool
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
data/lib/resque/pool.rb CHANGED
@@ -8,16 +8,14 @@ require 'yaml'
8
8
 
9
9
  module Resque
10
10
  class Pool
11
- include Logging
12
- attr_reader :config
13
- attr_reader :workers
14
-
15
- # CONSTANTS {{{
16
11
  SIG_QUEUE_MAX_SIZE = 5
17
12
  DEFAULT_WORKER_INTERVAL = 5
18
13
  QUEUE_SIGS = [ :QUIT, :INT, :TERM, :USR1, :USR2, :CONT, :HUP, :WINCH, ]
19
- CHUNK_SIZE=(16 * 1024)
20
- # }}}
14
+ CHUNK_SIZE = (16 * 1024)
15
+
16
+ include Logging
17
+ attr_reader :config
18
+ attr_reader :workers
21
19
 
22
20
  def initialize(config)
23
21
  init_config(config)
@@ -70,13 +68,14 @@ module Resque
70
68
  # }}}
71
69
  # Config: load config and config file {{{
72
70
 
71
+ def config_file
72
+ @config_file || (!@config && ::Resque::Pool.choose_config_file)
73
+ end
74
+
73
75
  def init_config(config)
74
- unless config
75
- raise ArgumentError,
76
- "No configuration found. Please setup config/resque-pool.yml"
77
- end
78
- if config.kind_of? String
79
- @config_file = config.to_s
76
+ case config
77
+ when String, nil
78
+ @config_file = config
80
79
  else
81
80
  @config = config.dup
82
81
  end
@@ -84,7 +83,11 @@ module Resque
84
83
  end
85
84
 
86
85
  def load_config
87
- @config_file and @config = YAML.load_file(@config_file)
86
+ if config_file
87
+ @config = YAML.load_file(config_file)
88
+ else
89
+ @config ||= {}
90
+ end
88
91
  environment and @config[environment] and config.merge!(@config[environment])
89
92
  config.delete_if {|key, value| value.is_a? Hash }
90
93
  end
@@ -124,9 +127,14 @@ module Resque
124
127
  end
125
128
  end
126
129
 
130
+ class QuitNowException < Exception; end
127
131
  # defer a signal for later processing in #join (master process)
128
132
  def trap_deferred(signal)
129
133
  trap(signal) do |sig_nr|
134
+ if @waiting_for_reaper && [:INT, :TERM].include?(signal)
135
+ log "Recieved #{signal}: short circuiting QUIT waitpid"
136
+ raise QuitNowException
137
+ end
130
138
  if sig_queue.size < SIG_QUEUE_MAX_SIZE
131
139
  sig_queue << signal
132
140
  awaken_master
@@ -146,8 +154,12 @@ module Resque
146
154
  log "#{signal}: sending to all workers"
147
155
  signal_all_workers(signal)
148
156
  when :HUP
149
- log "HUP: reload config file"
157
+ log "HUP: reload config file and reload logfiles"
150
158
  load_config
159
+ Logging.reopen_logs!
160
+ log "HUP: gracefully shutdown old children (which have old logfiles open)"
161
+ signal_all_workers(:QUIT)
162
+ log "HUP: new children will inherit new logfiles"
151
163
  maintain_worker_count
152
164
  when :WINCH
153
165
  log "WINCH: gracefully stopping all workers"
@@ -178,11 +190,19 @@ module Resque
178
190
  init_sig_handlers!
179
191
  maintain_worker_count
180
192
  procline("(started)")
181
- log "**** started master at PID: #{Process.pid}"
182
- log "**** Pool contains PIDs: #{all_pids.inspect}"
193
+ log "started manager"
194
+ report_worker_pool_pids
183
195
  self
184
196
  end
185
197
 
198
+ def report_worker_pool_pids
199
+ if workers.empty?
200
+ log "Pool is empty"
201
+ else
202
+ log "Pool contains worker PIDs: #{all_pids.inspect}"
203
+ end
204
+ end
205
+
186
206
  def join
187
207
  loop do
188
208
  reap_all_workers
@@ -195,7 +215,7 @@ module Resque
195
215
  end
196
216
  procline("(shutting down)")
197
217
  #stop # gracefully shutdown all workers on our way out
198
- log "**** master complete"
218
+ log "manager finished"
199
219
  #unlink_pid_safe(pid) if pid
200
220
  end
201
221
 
@@ -212,15 +232,17 @@ module Resque
212
232
  # worker process management {{{
213
233
 
214
234
  def reap_all_workers(waitpid_flags=Process::WNOHANG)
235
+ @waiting_for_reaper = waitpid_flags == 0
215
236
  begin
216
237
  loop do
238
+ # -1, wait for any child process
217
239
  wpid, status = Process.waitpid2(-1, waitpid_flags)
218
240
  wpid or break
219
241
  worker = delete_worker(wpid)
220
242
  # TODO: close any file descriptors connected to worker, if any
221
- log "** reaped #{status.inspect}, worker=#{worker.queues.join(",")}"
243
+ log "Reaped resque worker[#{status.pid}] (status: #{status.exitstatus}) queues: #{worker.queues.join(",")}"
222
244
  end
223
- rescue Errno::ECHILD
245
+ rescue Errno::ECHILD, QuitNowException
224
246
  end
225
247
  end
226
248
 
@@ -285,7 +307,7 @@ module Resque
285
307
  def spawn_worker!(queues)
286
308
  worker = create_worker(queues)
287
309
  pid = fork do
288
- log "*** Starting worker #{worker}"
310
+ log_worker "Starting worker #{worker}"
289
311
  call_after_prefork!
290
312
  reset_sig_handlers!
291
313
  #self_pipe.each {|io| io.close }
data/resque-pool.gemspec CHANGED
@@ -15,15 +15,20 @@ Gem::Specification.new do |s|
15
15
  saving memory (w/REE) and monitoring their uptime
16
16
  EOF
17
17
 
18
- s.add_dependency "resque", "~> 1.10"
18
+ s.add_dependency "resque", "~> 1.13"
19
19
  s.add_dependency "trollop", "~> 1.16"
20
20
  s.add_dependency "rake"
21
- s.add_development_dependency "rspec"
21
+ s.add_development_dependency "rspec", "~> 2.3.0"
22
+ s.add_development_dependency "cucumber", "~> 0.10.0"
23
+ s.add_development_dependency "aruba", "~> 0.3.2"
22
24
  s.add_development_dependency "SystemTimer" # to silence redis gem's warning
23
25
  s.add_development_dependency "bundler", "~> 1.0"
24
26
 
25
- s.files = `git ls-files`.split("\n")
26
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
27
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ # hidden files are automatically ignored by Dir.glob
28
+ ignore_patterns = %w[**/*.gem **/*.pid **/*.log pkg Gemfile.lock]
29
+ ignore_files = ignore_patterns.inject([]) {|a,p| a + Dir[p] }
30
+ s.files = Dir["**/*"] - ignore_files
31
+ s.test_files = Dir.glob("{spec,features}/**/*.{rb,yml,feature}")
32
+ s.executables = 'resque-pool'
28
33
  s.require_paths = ["lib"]
29
34
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec/spec_helper'
2
2
 
3
- Spec::Runner.configure do |config|
3
+ RSpec.configure do |config|
4
4
  config.after {
5
5
  Object.send(:remove_const, :RAILS_ENV) if defined? RAILS_ENV
6
6
  ENV.delete 'RACK_ENV'
@@ -80,6 +80,13 @@ describe Resque::Pool, "when loading the pool configuration from a Hash" do
80
80
 
81
81
  end
82
82
 
83
+ describe Resque::Pool, "given no configuration" do
84
+ subject { Resque::Pool.new(nil) }
85
+ it "should have no worker types" do
86
+ subject.config.should == {}
87
+ end
88
+ end
89
+
83
90
  describe Resque::Pool, "when loading the pool configuration from a file" do
84
91
 
85
92
  subject { Resque::Pool.new("spec/resque-pool.yml") }
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,3 @@
1
- require 'spec'
1
+ require 'rspec'
2
2
  $LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
3
3
  require 'resque/pool'
@@ -0,0 +1 @@
1
+ require 'resque/pool/tasks'
@@ -0,0 +1,3 @@
1
+ foo: 2
2
+ bar: 4
3
+ "baz,quux": 4
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque-pool
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - nicholas a. evans
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-18 00:00:00 -05:00
18
+ date: 2011-03-15 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -26,11 +26,11 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- hash: 27
29
+ hash: 21
30
30
  segments:
31
31
  - 1
32
- - 10
33
- version: "1.10"
32
+ - 13
33
+ version: "1.13"
34
34
  type: :runtime
35
35
  version_requirements: *id001
36
36
  - !ruby/object:Gem::Dependency
@@ -68,18 +68,52 @@ dependencies:
68
68
  requirement: &id004 !ruby/object:Gem::Requirement
69
69
  none: false
70
70
  requirements:
71
- - - ">="
71
+ - - ~>
72
72
  - !ruby/object:Gem::Version
73
73
  hash: 3
74
74
  segments:
75
+ - 2
76
+ - 3
75
77
  - 0
76
- version: "0"
78
+ version: 2.3.0
77
79
  type: :development
78
80
  version_requirements: *id004
79
81
  - !ruby/object:Gem::Dependency
80
- name: SystemTimer
82
+ name: cucumber
81
83
  prerelease: false
82
84
  requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ hash: 55
90
+ segments:
91
+ - 0
92
+ - 10
93
+ - 0
94
+ version: 0.10.0
95
+ type: :development
96
+ version_requirements: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ name: aruba
99
+ prerelease: false
100
+ requirement: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ~>
104
+ - !ruby/object:Gem::Version
105
+ hash: 23
106
+ segments:
107
+ - 0
108
+ - 3
109
+ - 2
110
+ version: 0.3.2
111
+ type: :development
112
+ version_requirements: *id006
113
+ - !ruby/object:Gem::Dependency
114
+ name: SystemTimer
115
+ prerelease: false
116
+ requirement: &id007 !ruby/object:Gem::Requirement
83
117
  none: false
84
118
  requirements:
85
119
  - - ">="
@@ -89,11 +123,11 @@ dependencies:
89
123
  - 0
90
124
  version: "0"
91
125
  type: :development
92
- version_requirements: *id005
126
+ version_requirements: *id007
93
127
  - !ruby/object:Gem::Dependency
94
128
  name: bundler
95
129
  prerelease: false
96
- requirement: &id006 !ruby/object:Gem::Requirement
130
+ requirement: &id008 !ruby/object:Gem::Requirement
97
131
  none: false
98
132
  requirements:
99
133
  - - ~>
@@ -104,7 +138,7 @@ dependencies:
104
138
  - 0
105
139
  version: "1.0"
106
140
  type: :development
107
- version_requirements: *id006
141
+ version_requirements: *id008
108
142
  description: " quickly and easily fork a pool of resque workers,\n saving memory (w/REE) and monitoring their uptime\n"
109
143
  email:
110
144
  - nick@ekenosen.net
@@ -115,33 +149,41 @@ extensions: []
115
149
  extra_rdoc_files: []
116
150
 
117
151
  files:
118
- - .gitignore
119
- - Changelog.md
120
- - Gemfile
121
- - Gemfile.lock
122
152
  - LICENSE.txt
153
+ - features/basic_daemon_config.feature
154
+ - features/support/aruba_daemon_support.rb
155
+ - features/support/env.rb
156
+ - features/step_definitions/resque-pool_steps.rb
157
+ - features/step_definitions/daemon_steps.rb
158
+ - bin/resque-pool
123
159
  - README.md
160
+ - spec/spec_helper.rb
161
+ - spec/resque_pool_spec.rb
162
+ - spec/resque-pool.yml
163
+ - spec/mock_config.rb
164
+ - Changelog.md
124
165
  - Rakefile
125
- - bin/resque-pool
126
- - config/alternate.yml
127
- - config/resque-pool.yml
128
- - examples/Rakefile
166
+ - examples/Gemfile.lock
129
167
  - examples/chef_cookbook/recipes/default.rb
130
168
  - examples/chef_cookbook/templates/default/initd.erb
131
169
  - examples/chef_cookbook/templates/default/monitrc.erb
132
170
  - examples/rails-resque.rake
133
171
  - examples/resque-pool.yml
172
+ - examples/Rakefile
173
+ - examples/log/resque-pool.stdout.log.2
174
+ - examples/Gemfile
175
+ - resque-pool.gemspec
176
+ - tmp/aruba/Rakefile
177
+ - tmp/aruba/config/resque-pool.yml
134
178
  - lib/resque/pool.rb
135
- - lib/resque/pool/cli.rb
136
- - lib/resque/pool/logging.rb
137
- - lib/resque/pool/pooled_worker.rb
138
179
  - lib/resque/pool/tasks.rb
180
+ - lib/resque/pool/cli.rb
139
181
  - lib/resque/pool/version.rb
140
- - resque-pool.gemspec
141
- - spec/mock_config.rb
142
- - spec/resque-pool.yml
143
- - spec/resque_pool_spec.rb
144
- - spec/spec_helper.rb
182
+ - lib/resque/pool/pooled_worker.rb
183
+ - lib/resque/pool/logging.rb
184
+ - config/cucumber.yml
185
+ - config/alternate.yml
186
+ - Gemfile
145
187
  has_rdoc: true
146
188
  homepage: http://github.com/nevans/resque-pool
147
189
  licenses: []
@@ -176,5 +218,13 @@ rubygems_version: 1.3.7
176
218
  signing_key:
177
219
  specification_version: 3
178
220
  summary: quickly and easily fork a pool of resque workers
179
- test_files: []
180
-
221
+ test_files:
222
+ - spec/spec_helper.rb
223
+ - spec/resque_pool_spec.rb
224
+ - spec/mock_config.rb
225
+ - spec/resque-pool.yml
226
+ - features/support/aruba_daemon_support.rb
227
+ - features/support/env.rb
228
+ - features/step_definitions/resque-pool_steps.rb
229
+ - features/step_definitions/daemon_steps.rb
230
+ - features/basic_daemon_config.feature
data/.gitignore DELETED
@@ -1,5 +0,0 @@
1
- pkg/*
2
- *.gem
3
- .bundle
4
- *.log
5
- *.pid
data/Gemfile.lock DELETED
@@ -1,51 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- resque-pool (0.0.12.0.alpha)
5
- rake
6
- resque (~> 1.10)
7
- trollop (~> 1.16)
8
-
9
- GEM
10
- remote: http://rubygems.org/
11
- specs:
12
- SystemTimer (1.2.1)
13
- diff-lcs (1.1.2)
14
- json (1.4.6)
15
- rack (1.2.1)
16
- rake (0.8.7)
17
- redis (2.1.1)
18
- redis-namespace (0.8.0)
19
- redis (< 3.0.0)
20
- resque (1.10.0)
21
- json (~> 1.4.6)
22
- redis-namespace (~> 0.8.0)
23
- sinatra (>= 0.9.2)
24
- vegas (~> 0.1.2)
25
- rspec (2.4.0)
26
- rspec-core (~> 2.4.0)
27
- rspec-expectations (~> 2.4.0)
28
- rspec-mocks (~> 2.4.0)
29
- rspec-core (2.4.0)
30
- rspec-expectations (2.4.0)
31
- diff-lcs (~> 1.1.2)
32
- rspec-mocks (2.4.0)
33
- sinatra (1.1.2)
34
- rack (~> 1.1)
35
- tilt (~> 1.2)
36
- tilt (1.2.1)
37
- trollop (1.16.2)
38
- vegas (0.1.8)
39
- rack (>= 1.0.0)
40
-
41
- PLATFORMS
42
- ruby
43
-
44
- DEPENDENCIES
45
- SystemTimer
46
- bundler (~> 1.0)
47
- rake
48
- resque (~> 1.10)
49
- resque-pool!
50
- rspec
51
- trollop (~> 1.16)
@@ -1,7 +0,0 @@
1
- foo: 1
2
- bar: 1
3
- baz: 1
4
- "foo,bar": 2
5
- "foo,bar,baz": 4
6
-
7
-