resque-pool-vinted 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,138 @@
1
+ require 'trollop'
2
+ require 'resque/pool'
3
+ require 'fileutils'
4
+
5
+ module Resque
6
+ class Pool
7
+ module CLI
8
+ extend self
9
+
10
+ def run
11
+ opts = parse_options
12
+ daemonize if opts[:daemon]
13
+ manage_pidfile opts[:pidfile]
14
+ redirect opts
15
+ setup_environment opts
16
+ set_pool_options opts
17
+ start_pool
18
+ end
19
+
20
+ def parse_options
21
+ opts = Trollop::options do
22
+ version "resque-pool #{VERSION} (c) nicholas a. evans"
23
+ banner <<-EOS
24
+ resque-pool is the best way to manage a group (pool) of resque workers
25
+
26
+ When daemonized, stdout and stderr default to resque-pool.stdxxx.log files in
27
+ the log directory and pidfile defaults to resque-pool.pid in the current dir.
28
+
29
+ Usage:
30
+ resque-pool [options]
31
+ where [options] are:
32
+ EOS
33
+ opt :config, "Alternate path to config file", :type => String, :short => "-c"
34
+ opt :appname, "Alternate appname", :type => String, :short => "-a"
35
+ opt :daemon, "Run as a background daemon", :default => false, :short => "-d"
36
+ opt :stdout, "Redirect stdout to logfile", :type => String, :short => '-o'
37
+ opt :stderr, "Redirect stderr to logfile", :type => String, :short => '-e'
38
+ opt :nosync, "Don't sync logfiles on every write"
39
+ opt :pidfile, "PID file location", :type => String, :short => "-p"
40
+ opt :environment, "Set RAILS_ENV/RACK_ENV/RESQUE_ENV", :type => String, :short => "-E"
41
+ opt :term_graceful_wait, "On TERM signal, wait for workers to shut down gracefully"
42
+ opt :term_graceful, "On TERM signal, shut down workers gracefully"
43
+ opt :term_immediate, "On TERM signal, shut down workers immediately (default)"
44
+ opt :single_process_group, "Workers remain in the same process group as the master", :default => false
45
+ end
46
+ if opts[:daemon]
47
+ opts[:stdout] ||= "log/resque-pool.stdout.log"
48
+ opts[:stderr] ||= "log/resque-pool.stderr.log"
49
+ opts[:pidfile] ||= "tmp/pids/resque-pool.pid"
50
+ end
51
+ opts
52
+ end
53
+
54
+ def daemonize
55
+ raise 'First fork failed' if (pid = fork) == -1
56
+ exit unless pid.nil?
57
+ Process.setsid
58
+ raise 'Second fork failed' if (pid = fork) == -1
59
+ exit unless pid.nil?
60
+ end
61
+
62
+ def manage_pidfile(pidfile)
63
+ return unless pidfile
64
+ pid = Process.pid
65
+ if File.exist? pidfile
66
+ if process_still_running? pidfile
67
+ raise "Pidfile already exists at #{pidfile} and process is still running."
68
+ else
69
+ File.delete pidfile
70
+ end
71
+ else
72
+ FileUtils.mkdir_p File.dirname(pidfile)
73
+ end
74
+ File.open pidfile, "w" do |f|
75
+ f.write pid
76
+ end
77
+ at_exit do
78
+ if Process.pid == pid
79
+ File.delete pidfile
80
+ end
81
+ end
82
+ end
83
+
84
+ def process_still_running?(pidfile)
85
+ old_pid = open(pidfile).read.strip.to_i
86
+ Process.kill 0, old_pid
87
+ true
88
+ rescue Errno::ESRCH
89
+ false
90
+ rescue Errno::EPERM
91
+ true
92
+ rescue ::Exception => e
93
+ $stderr.puts "While checking if PID #{old_pid} is running, unexpected #{e.class}: #{e}"
94
+ true
95
+ end
96
+
97
+ def redirect(opts)
98
+ $stdin.reopen '/dev/null' if opts[:daemon]
99
+ # need to reopen as File, or else Resque::Pool::Logging.reopen_logs! won't work
100
+ out = File.new(opts[:stdout], "a") if opts[:stdout] && !opts[:stdout].empty?
101
+ err = File.new(opts[:stderr], "a") if opts[:stderr] && !opts[:stderr].empty?
102
+ $stdout.reopen out if out
103
+ $stderr.reopen err if err
104
+ $stdout.sync = $stderr.sync = true unless opts[:nosync]
105
+ end
106
+
107
+ # TODO: global variables are not the best way
108
+ def set_pool_options(opts)
109
+ if opts[:daemon]
110
+ Resque::Pool.handle_winch = true
111
+ end
112
+ if opts[:term_graceful_wait]
113
+ Resque::Pool.term_behavior = "graceful_worker_shutdown_and_wait"
114
+ elsif opts[:term_graceful]
115
+ Resque::Pool.term_behavior = "graceful_worker_shutdown"
116
+ end
117
+ end
118
+
119
+ def setup_environment(opts)
120
+ Resque::Pool.app_name = opts[:appname] if opts[:appname]
121
+ ENV["RACK_ENV"] = ENV["RAILS_ENV"] = ENV["RESQUE_ENV"] = opts[:environment] if opts[:environment]
122
+ Resque::Pool.log "Resque Pool running in #{ENV["RAILS_ENV"] || "development"} environment"
123
+ ENV["RESQUE_POOL_CONFIG"] = opts[:config] if opts[:config]
124
+ Resque::Pool.single_process_group = opts[:single_process_group]
125
+ end
126
+
127
+ def start_pool
128
+ require 'rake'
129
+ require 'resque/pool/tasks'
130
+ Rake.application.init
131
+ Rake.application.load_rakefile
132
+ Rake.application["resque:pool"].invoke
133
+ end
134
+
135
+ end
136
+ end
137
+ end
138
+
@@ -0,0 +1,65 @@
1
+ module Resque
2
+ class Pool
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
36
+
37
+ # Given a string, sets the procline ($0)
38
+ # Procline is always in the format of:
39
+ # resque-pool-master: STRING
40
+ def procline(string)
41
+ $0 = "resque-pool-master#{app}: #{string}"
42
+ end
43
+
44
+ # TODO: make this use an actual logger
45
+ def log(message)
46
+ puts "resque-pool-manager#{app}[#{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#{app}[#{Process.pid}]: #{message}"
53
+ #$stdout.fsync
54
+ end
55
+
56
+ # Include optional app name in procline
57
+ def app
58
+ app_name = self.respond_to?(:app_name) && self.app_name
59
+ app_name ||= self.class.respond_to?(:app_name) && self.class.app_name
60
+ app_name ? "[#{app_name}]" : ""
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ require 'resque/worker'
2
+
3
+ class Resque::Pool
4
+ module PooledWorker
5
+ def shutdown_with_pool
6
+ shutdown_without_pool || Process.ppid == 1
7
+ end
8
+
9
+ def self.included(base)
10
+ base.instance_eval do
11
+ alias_method :shutdown_without_pool, :shutdown?
12
+ alias_method :shutdown?, :shutdown_with_pool
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+
19
+ Resque::Worker.class_eval do
20
+ include Resque::Pool::PooledWorker
21
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'resque/tasks'
3
+
4
+ namespace :resque do
5
+
6
+ # resque worker config (not pool related). e.g. hoptoad, rails environment
7
+ task :setup
8
+
9
+ namespace :pool do
10
+ # resque pool config. e.g. after_prefork connection handling
11
+ task :setup
12
+ end
13
+
14
+ desc "Launch a pool of resque workers"
15
+ task :pool => %w[resque:preload resque:setup resque:pool:setup] do
16
+ require 'resque/pool'
17
+ Resque::Pool.run
18
+ end
19
+
20
+ end
@@ -0,0 +1,5 @@
1
+ module Resque
2
+ class Pool
3
+ VERSION = "0.4.0.rc1"
4
+ end
5
+ end
@@ -0,0 +1,88 @@
1
+ .\" generated with Ronn/v0.7.3
2
+ .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
+ .
4
+ .TH "RESQUE\-POOL" "1" "June 2012" "RESQUE-POOL 0.4.0.DEV" "RESQUE-POOL"
5
+ .
6
+ .SH "NAME"
7
+ \fBresque\-pool\fR \- resque worker pool management
8
+ .
9
+ .SH "SYNOPSIS"
10
+ \fBresque\-pool\fR \fIoptions\fR
11
+ .
12
+ .SH "DESCRIPTION"
13
+ \fBResque\-pool\fR is the best way to manage a group (pool) of resque workers\.
14
+ .
15
+ .P
16
+ When resque\-pool(1) is daemonized the \fBstdout\fR and \fBstderr\fR output streams are redirected to \fBresque\-pool\.stdxxx\.log\fR log files in the \fBlog\fR directory\. Additionally the PID file defaults to \fBresque\-pool\.pid\fR in the \fBtmp/pids\fR directory\.
17
+ .
18
+ .SH "OPTIONS"
19
+ .
20
+ .IP "\(bu" 4
21
+ \fB\-c, \-\-config\fR \fIfile\fR: Uses the configuration specified in the \fIfile\fR provided instead of searching in the current and \fBconfig\fR directories for \fBresque\-pool\.yml\fR\.
22
+ .
23
+ .IP "\(bu" 4
24
+ \fB\-a, \-\-appname\fR \fIname\fR: Specifies the app name to be used for logging and procline\. If not specified, this defaults to the current working directory\.
25
+ .
26
+ .IP "\(bu" 4
27
+ \fB\-d, \-\-daemon\fR: Runs \fBresque\-pool\fR in the background as a daemon process\. This will redirect \fBstdout\fR and \fBstderr\fR to log files and write a PID file\.
28
+ .
29
+ .IP "\(bu" 4
30
+ \fB\-o, \-\-stdout\fR \fIfile\fR: Writes the normal log output to \fIfile\fR instead of printing to the terminal\. When running as a daemon this defaults to the path \fBlog/resque\-pool\.stdout\.log\fR\.
31
+ .
32
+ .IP "\(bu" 4
33
+ \fB\-e, \-\-stderr\fR \fIfile\fR: Writes the standard error output to \fIfile\fR instead of printing to the terminal\. When running as a daemon this defaults to the path \fBlog/resque\-pool\.stderr\.log\fR\.
34
+ .
35
+ .IP "\(bu" 4
36
+ \fB\-\-nosync\fR Allows writes to \fBstdout\fR and \fBstderr\fR to be buffered\.
37
+ .
38
+ .IP "\(bu" 4
39
+ \fB\-p, \-\-pidfile\fR \fIfile\fR: Writes the PID to the \fIfile\fR\. When running as a daemon this defaults to \fBtmp/pids/resque\-pool\.pid\fR\.
40
+ .
41
+ .IP "\(bu" 4
42
+ \fB\-E, \-\-environment\fR \fIname\fR: Specifies the environment \fIname\fR to be set for \fBRAILS_ENV\fR, \fBRACK_ENV\fR and \fBRESQUE_ENV\fR which will be passed on to the pooled resque workers\.
43
+ .
44
+ .IP "\(bu" 4
45
+ \fB\-\-term\-graceful\-wait\fR: Configure TERM signal handling so the master will gracefully request worker shut downs (via \fBQUIT\fR) and wait for the workers to quit before shutting down itself\. This is the same behavior as the \fBQUIT\fR signal\.
46
+ .
47
+ .IP "\(bu" 4
48
+ \fB\-\-term\-graceful\fR: Configure TERM signal handling so the master will gracefully request worker shut downs (via \fBQUIT\fR) but shut itself down immediately\. This the same behavior as the \fBINT\fR signal\.
49
+ .
50
+ .IP "\(bu" 4
51
+ \fB\-\-term\-immediate\fR: Configure TERM signal handling so the master will request imediate worker shut downs (via \fBINT\fR) and shut itself down immediately\. This is the default \fBTERM\fR signal behavior\.
52
+ .
53
+ .IP "" 0
54
+ .
55
+ .SH "HISTORY"
56
+ .
57
+ .TP
58
+ \fBv0\.3\.0\fR
59
+ Support for ruby 1\.9, resque 1\.20\.
60
+ .
61
+ .br
62
+ Added appname for logging\.
63
+ .
64
+ .br
65
+ Minor bugfixes\.
66
+ .
67
+ .TP
68
+ \fBv0\.2\.0\fR
69
+ Support for reloading logs and workers with \fBHUP\fR signal
70
+ .
71
+ .br
72
+ Cleans up PID file on startup
73
+ .
74
+ .br
75
+ Fixed \fB\-c, \-\-config\fR option\.
76
+ .
77
+ .TP
78
+ \fBv0\.1\.0\fR
79
+ \fBresque\-pool\fR command line interface added
80
+ .
81
+ .SH "AUTHOR"
82
+ Nicholas Evans
83
+ .
84
+ .SH "COPYRIGHT"
85
+ Copyright (C) 2010 by Nicholas Evans \fInick@ekenosen\.net\fR, et al\.
86
+ .
87
+ .SH "SEE ALSO"
88
+ resque\-pool\.yml(5)
@@ -0,0 +1,92 @@
1
+ resque-pool(1) -- resque worker pool management
2
+ ================================================
3
+
4
+ ## SYNOPSIS
5
+
6
+ `resque-pool` [options]
7
+
8
+ ## DESCRIPTION
9
+
10
+ **Resque-pool** is the best way to manage a group (pool) of resque workers.
11
+
12
+ When resque-pool(1) is daemonized the `stdout` and `stderr` output streams
13
+ are redirected to `resque-pool.stdxxx.log` log files in the `log` directory.
14
+ Additionally the PID file defaults to `resque-pool.pid` in the `tmp/pids`
15
+ directory.
16
+
17
+ ## OPTIONS
18
+
19
+ * `-c, --config` <file>:
20
+ Uses the configuration specified in the <file> provided instead of
21
+ searching in the current and `config` directories for `resque-pool.yml`.
22
+
23
+ * `-a, --appname` <name>:
24
+ Specifies the app name to be used for logging and procline. If not
25
+ specified, this defaults to the current working directory.
26
+
27
+ * `-d, --daemon`:
28
+ Runs `resque-pool` in the background as a daemon process. This will
29
+ redirect `stdout` and `stderr` to log files and write a PID file.
30
+
31
+ * `-o, --stdout` <file>:
32
+ Writes the normal log output to <file> instead of printing to the
33
+ terminal. When running as a daemon this defaults to the path
34
+ `log/resque-pool.stdout.log`.
35
+
36
+ * `-e, --stderr` <file>:
37
+ Writes the standard error output to <file> instead of printing to the
38
+ terminal. When running as a daemon this defaults to the path
39
+ `log/resque-pool.stderr.log`.
40
+
41
+ * `--nosync`
42
+ Allows writes to `stdout` and `stderr` to be buffered.
43
+
44
+ * `-p, --pidfile` <file>:
45
+ Writes the PID to the <file>. When running as a daemon this defaults
46
+ to `tmp/pids/resque-pool.pid`.
47
+
48
+ * `-E, --environment` <name>:
49
+ Specifies the environment <name> to be set for `RAILS_ENV`, `RACK_ENV`
50
+ and `RESQUE_ENV` which will be passed on to the pooled resque workers.
51
+
52
+ * `--term-graceful-wait`:
53
+ Configure TERM signal handling so the master will gracefully request worker
54
+ shut downs (via `QUIT`) and wait for the workers to quit before shutting
55
+ down itself. This is the same behavior as the `QUIT` signal.
56
+
57
+ * `--term-graceful`:
58
+ Configure TERM signal handling so the master will gracefully request worker
59
+ shut downs (via `QUIT`) but shut itself down immediately. This the same
60
+ behavior as the `INT` signal.
61
+
62
+ * `--term-immediate`:
63
+ Configure TERM signal handling so the master will request imediate worker
64
+ shut downs (via `INT`) and shut itself down immediately. This is the
65
+ default `TERM` signal behavior.
66
+
67
+ ## HISTORY
68
+
69
+ * `v0.3.0`:
70
+ Support for ruby 1.9, resque 1.20.<br>
71
+ Added appname for logging.<br>
72
+ Minor bugfixes.
73
+
74
+ * `v0.2.0`:
75
+ Support for reloading logs and workers with `HUP` signal<br>
76
+ Cleans up PID file on startup<br>
77
+ Fixed `-c, --config` option.
78
+
79
+ * `v0.1.0`:
80
+ `resque-pool` command line interface added
81
+
82
+ ## AUTHOR
83
+
84
+ Nicholas Evans
85
+
86
+ ## COPYRIGHT
87
+
88
+ Copyright (C) 2010 by Nicholas Evans <nick@ekenosen.net>, et al.
89
+
90
+ ## SEE ALSO
91
+
92
+ resque-pool.yml(5)
@@ -0,0 +1,46 @@
1
+ .\" generated with Ronn/v0.7.3
2
+ .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
+ .
4
+ .TH "RESQUE\-POOL\.YML" "5" "May 2012" "RESQUE-POOL 0.3.0.DEV" "RESQUE-POOL"
5
+ .
6
+ .SH "NAME"
7
+ \fBresque\-pool\.yml\fR \- resque\-pool pool configuration
8
+ .
9
+ .SH "SYNOPSIS"
10
+ \fBresque\-pool\.yml\fR
11
+ .
12
+ .br
13
+ \fBconfig/resque\-pool\.yml\fR
14
+ .
15
+ .SH "DESCRIPTION"
16
+ resque\-pool(1) reads pool configuration data from \fBresque\-pool\.yml\fR (or the file specified with \fB\-c\fR on the command line)\. The file contains queue\-worker\-count pairs, one per line\. The configuration file supports both using root level defaults as well as environment specific overrides (\fBRACK_ENV\fR, \fBRAILS_ENV\fR, and \fBRESQUE_ENV\fR environment variables can be used to determine environment)\.
17
+ .
18
+ .P
19
+ An example configuration
20
+ .
21
+ .IP "" 4
22
+ .
23
+ .nf
24
+
25
+ foo: 1
26
+ bar: 2
27
+ "foo,bar,baz": 1
28
+
29
+ production:
30
+ "foo,bar,baz": 4
31
+ .
32
+ .fi
33
+ .
34
+ .IP "" 0
35
+ .
36
+ .P
37
+ will create 7 workers in production and 4 in other environment configurations\. The simpler worker definition \fBfoo: 1\fR will create 1 worker for the \fBfoo\fR queue, the more complicated \fBfoo,bar,baz: 1\fR will create 1 worker for the queues \fBfoo\fR, \fBbar\fR and \fBbaz\fR\.
38
+ .
39
+ .SH "AUTHOR"
40
+ Nicholas Evans
41
+ .
42
+ .SH "COPYRIGHT"
43
+ Copyright (C) 2010 by Nicholas Evans \fInick@ekenosen\.net\fR, et al\.
44
+ .
45
+ .SH "SEE ALSO"
46
+ resque\-pool(1)