forker 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +57 -0
- data/lib/forker.rb +124 -0
- metadata +82 -0
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Goals
|
2
|
+
|
3
|
+
* Simplest code possible to daemonize code, redirect output and manage the
|
4
|
+
pidfile.
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
require 'forker'
|
9
|
+
Forker.fork(
|
10
|
+
:log => "/dev/null", # Default value
|
11
|
+
:pid => "/var/run/#{File.basename($0)}.pid", # Default value
|
12
|
+
:chdir => false, # Default value
|
13
|
+
:umask => false # Default value
|
14
|
+
)
|
15
|
+
|
16
|
+
# Do stuff in daemonized proc...
|
17
|
+
|
18
|
+
## Or for a simple start/stop script
|
19
|
+
|
20
|
+
#!/usr/bin/env ruby
|
21
|
+
# Example usage from command line:
|
22
|
+
# ./bin/myscript start --logfile LOGFILE --pidfile PIDFILE
|
23
|
+
# ./bin/myscript stop --logfile LOGFILE --pidfile PIDFILE
|
24
|
+
|
25
|
+
require 'forker'
|
26
|
+
Forker::CLI.run(ARGV)
|
27
|
+
|
28
|
+
## Example bin/worker script for Resque
|
29
|
+
|
30
|
+
#!/usr/bin/env ruby
|
31
|
+
|
32
|
+
# Default to production, this script can't be passed env vars on the prod servers
|
33
|
+
ENV['RAILS_ENV'] ||= 'production'
|
34
|
+
|
35
|
+
# Simulate calling rake environment
|
36
|
+
$rails_rake_task = true
|
37
|
+
|
38
|
+
# Load rails env
|
39
|
+
require File.expand_path("../config/environment", File.dirname(__FILE__))
|
40
|
+
|
41
|
+
require 'forker'
|
42
|
+
Forker::CLI.run(ARGV)
|
43
|
+
|
44
|
+
worker = nil
|
45
|
+
queues = (ENV['QUEUES'] || ENV['QUEUE'] || '*').to_s.split(',')
|
46
|
+
|
47
|
+
begin
|
48
|
+
worker = Resque::Worker.new(*queues)
|
49
|
+
worker.verbose = ENV['LOGGING'] || ENV['VERBOSE']
|
50
|
+
worker.very_verbose = ENV['VVERBOSE']
|
51
|
+
rescue Resque::NoQueueError
|
52
|
+
abort "set QUEUE env var, e.g. $ QUEUE=critical,high,low rake resque:work"
|
53
|
+
end
|
54
|
+
|
55
|
+
puts "*** Starting worker in #{ENV['RAILS_ENV']} environment: #{worker}"
|
56
|
+
|
57
|
+
worker.work(ENV['INTERVAL'] || 5) # interval, will block
|
data/lib/forker.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# This gem follows best practices for daemonizing processes in a UNIX
|
2
|
+
# environment with as little fluff as possible. Forks once, calls `setsid`,
|
3
|
+
# and forks again. STDIN, STDOUT, STDERR are all redirected to /dev/null by
|
4
|
+
# default. We'll manage the pidfile also.
|
5
|
+
#
|
6
|
+
# `chdir` and `umask` are optional precautions:
|
7
|
+
#
|
8
|
+
# * `chdir` is a safeguard against problems that would occur is you tried to
|
9
|
+
# launch a daemon process on a mounted filesystem
|
10
|
+
# * `umask` gives your daemon process more control over file creation
|
11
|
+
# permissions
|
12
|
+
#
|
13
|
+
# Notes
|
14
|
+
# $$ = Process.pid
|
15
|
+
|
16
|
+
require 'system_timer'
|
17
|
+
|
18
|
+
module Forker
|
19
|
+
module CLI
|
20
|
+
# You can use this if your daemon is simple enough or write your own and
|
21
|
+
# use Forker#fork! directly
|
22
|
+
def self.run(argv)
|
23
|
+
require 'optparse'
|
24
|
+
options = {}
|
25
|
+
opts = OptionParser.new do |opts|
|
26
|
+
opts.banner = "Usage: #{File.basename($0)} [start|stop] -p /path/to/pidfile.pid"
|
27
|
+
|
28
|
+
opts.on("-l", "--logfile LOGFILE", "redirect output to this location") do |logfile|
|
29
|
+
options[:log] = logfile
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-p", "--pidfile PIDFILE", "save pidfile to this location") do |pidfile|
|
33
|
+
options[:pid] = pidfile
|
34
|
+
end
|
35
|
+
end
|
36
|
+
opts.parse!(argv)
|
37
|
+
|
38
|
+
if options[:pid].nil?
|
39
|
+
puts opts
|
40
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
case argv.first
|
44
|
+
when "start"
|
45
|
+
Forker.fork!(options)
|
46
|
+
when "stop"
|
47
|
+
Forker.kill(options)
|
48
|
+
exit
|
49
|
+
else
|
50
|
+
puts opts
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.fork!(opts={})
|
57
|
+
opts = { :log => "/dev/null", :pid => "/var/run/#{File.basename($0)}.pid" }.merge(opts)
|
58
|
+
|
59
|
+
$stdout.sync = $stderr.sync = true
|
60
|
+
$stdin.reopen("/dev/null")
|
61
|
+
|
62
|
+
exit if fork
|
63
|
+
|
64
|
+
Process.setsid
|
65
|
+
|
66
|
+
exit if fork
|
67
|
+
|
68
|
+
Dir.chdir("/") if opts[:chdir]
|
69
|
+
File.umask(0000) if opts[:umask]
|
70
|
+
|
71
|
+
if File.exist?(opts[:pid])
|
72
|
+
begin
|
73
|
+
existing_pid = File.read(opts[:pid]).to_i
|
74
|
+
Process.kill(0, existing_pid) # See if proc exists
|
75
|
+
abort "error: existing process #{existing_pid} using this pidfile, exiting"
|
76
|
+
rescue Errno::ESRCH
|
77
|
+
puts "warning: removing stale pidfile with pid #{existing_pid}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
File.open(opts[:pid], 'w') { |f| f.write($$) }
|
82
|
+
|
83
|
+
at_exit do
|
84
|
+
( File.read(opts[:pid]).to_i == $$ and File.unlink(opts[:pid]) ) rescue nil
|
85
|
+
end
|
86
|
+
|
87
|
+
puts "forked process is #{$$}"
|
88
|
+
puts "output redirected to #{opts[:log]}"
|
89
|
+
|
90
|
+
$stdout.reopen(opts[:log], 'a')
|
91
|
+
$stderr.reopen(opts[:log], 'a')
|
92
|
+
$stdout.sync = $stderr.sync = true
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.kill(opts={})
|
96
|
+
begin
|
97
|
+
pid = File.read(opts[:pid]).to_i
|
98
|
+
sec = 60 # Seconds to wait before force killing
|
99
|
+
Process.kill("TERM", pid)
|
100
|
+
|
101
|
+
begin
|
102
|
+
SystemTimer.timeout(sec) do
|
103
|
+
loop do
|
104
|
+
puts "waiting #{sec} seconds for #{pid} before sending KILL"
|
105
|
+
Process.kill(0, pid) # See if proc exists
|
106
|
+
|
107
|
+
sec -= 1
|
108
|
+
sleep 1
|
109
|
+
end
|
110
|
+
end
|
111
|
+
rescue Errno::ESRCH
|
112
|
+
puts "killed process #{pid}"
|
113
|
+
rescue Timeout::Error
|
114
|
+
Process.kill("KILL", pid)
|
115
|
+
puts "force killed process #{pid}"
|
116
|
+
end
|
117
|
+
|
118
|
+
rescue Errno::ENOENT
|
119
|
+
puts "warning: pidfile #{opts[:pid]} does not exist"
|
120
|
+
rescue Errno::ESRCH
|
121
|
+
puts "warning: process #{pid} does not exist"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: forker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 1.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ben Marini
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-09-27 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: SystemTimer
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 11
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
version: "1.2"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
description: Fork your ruby code with confidence
|
37
|
+
email: bmarini@gmail.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- lib/forker.rb
|
46
|
+
- README.md
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://github.com/bmarini/forker
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.3.7
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Fork your ruby code with confidence
|
81
|
+
test_files: []
|
82
|
+
|