Class: Process::Daemon

Inherits:
Object
  • Object
show all
Defined in:
lib/process/daemon.rb,
lib/process/daemon/version.rb,
lib/process/daemon/log_file.rb,
lib/process/daemon/controller.rb,
lib/process/daemon/priviledges.rb,
lib/process/daemon/process_file.rb

Overview

This class is the base daemon class. If you are writing a daemon, you should inherit from this class.

The basic structure of a daemon is as follows: class Server < Process::Daemon def startup # Long running process, e.g. web server, game server, etc. end def shutdown # Stop the process above, usually called on SIGINT. end end Server.daemonize

The base directory specifies a path such that:

working_directory = "."
log_directory = #{working_directory}/log
log_file_path = #{log_directory}/#{name}.log
runtime_directory = #{working_directory}/run
process_file_path = #{runtime_directory}/#{name}.pid

Defined Under Namespace

Modules: Priviledges Classes: Controller, LogFile, ProcessFile

Constant Summary collapse

VERSION =
"0.5.4"
TIMEOUT =

Daemon startup timeout

5

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(working_directory = ".") ⇒ Daemon

Returns a new instance of Daemon.



52
53
54
# File 'lib/process/daemon.rb', line 52

def initialize(working_directory = ".")
	@working_directory = working_directory
end

Instance Attribute Details

#titleObject

Returns the value of attribute title.



136
137
138
# File 'lib/process/daemon.rb', line 136

def title
  @title
end

#working_directoryObject (readonly)

The directory the daemon will run in.



62
63
64
# File 'lib/process/daemon.rb', line 62

def working_directory
  @working_directory
end

Class Method Details

.controller(options = {}) ⇒ Object

The process controller, responsible for managing the daemon process start, stop, restart, etc.



166
167
168
# File 'lib/process/daemon.rb', line 166

def self.controller(options = {})
	@controller ||= Controller.new(instance, options)
end

.daemonize(*args) ⇒ Object

The main entry point for daemonized scripts.



171
172
173
174
175
176
177
# File 'lib/process/daemon.rb', line 171

def self.daemonize(*args)
	# Wish Ruby 2.0 kwargs were backported to 1.9.3... oh well:
	options = (args.last === Hash) ? args.pop : {}
	argv = (args.last === Array) ? args.pop : ARGV
	
	controller(options).daemonize(argv)
end

.instanceObject

A shared instance of the daemon.



161
162
163
# File 'lib/process/daemon.rb', line 161

def self.instance
	@instance ||= self.new
end

.startObject

Start the daemon instance.



180
181
182
# File 'lib/process/daemon.rb', line 180

def self.start
	controller.start
end

.statusObject

Check if the daemon is runnning or not.



190
191
192
# File 'lib/process/daemon.rb', line 190

def self.status
	controller.status
end

.stopObject

Stop the daemon instance.



185
186
187
# File 'lib/process/daemon.rb', line 185

def self.stop
	controller.stop
end

.working_directoryObject



118
119
120
# File 'lib/process/daemon.rb', line 118

def self.working_directory
	@working_directory
end

Instance Method Details

#crashed?Boolean

Check the last few lines of the log file to find out if the daemon crashed.

Returns:

  • (Boolean)


101
102
103
104
105
106
107
108
109
110
111
# File 'lib/process/daemon.rb', line 101

def crashed?
	count = 3
	
	LogFile.open(log_file_path).tail_log do |line|
		return true if line.match("=== Daemon Crashed")

		break if (count -= 1) == 0
	end

	return false
end

#log_directoryObject

Return the directory to store log files in.



65
66
67
# File 'lib/process/daemon.rb', line 65

def log_directory
	File.join(working_directory, "log")
end

#log_file_pathObject

Standard log file for stdout and stderr.



70
71
72
# File 'lib/process/daemon.rb', line 70

def log_file_path
	File.join(log_directory, "#{name}.log")
end

#mark_logObject

Mark the output log.



85
86
87
88
89
# File 'lib/process/daemon.rb', line 85

def mark_log
	File.open(log_file_path, "a") do |log_file|
		log_file.puts "=== Log Marked @ #{Time.now.to_s} [#{Process.pid}] ==="
	end
end

#nameObject

Return the name of the daemon



57
58
59
# File 'lib/process/daemon.rb', line 57

def name
	return self.class.name.gsub(/[^a-zA-Z0-9]+/, '-')
end

#preforkObject

The main function to setup any environment required by the daemon



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/process/daemon.rb', line 114

def prefork
	# We freeze the working directory because it can't change after forking:
	@working_directory = File.expand_path(working_directory)
	
	def self.working_directory
		@working_directory
	end
	
	FileUtils.mkdir_p(log_directory)
	FileUtils.mkdir_p(runtime_directory)
end

#process_file_pathObject

Standard location of process pid file.



80
81
82
# File 'lib/process/daemon.rb', line 80

def process_file_path
	File.join(runtime_directory, "#{name}.pid")
end

#runObject



149
150
151
152
153
154
155
156
157
158
# File 'lib/process/daemon.rb', line 149

def run
	
	self.title = self.name
	
	trap("INT") do
		shutdown
	end
	
	startup
end

#runtime_directoryObject

Runtime data directory for the daemon.



75
76
77
# File 'lib/process/daemon.rb', line 75

def runtime_directory
	File.join(working_directory, "run")
end

#shutdownObject

The main function to stop the daemon



131
132
133
134
# File 'lib/process/daemon.rb', line 131

def shutdown
	# Interrupt all children processes, preferably to stop them so that they are not left behind.
	Process.kill(:INT, 0)
end

#startupObject

The main function to start the daemon



127
128
# File 'lib/process/daemon.rb', line 127

def startup
end

#tail_log(output) ⇒ Object

Prints some information relating to daemon startup problems.



92
93
94
95
96
97
98
# File 'lib/process/daemon.rb', line 92

def tail_log(output)
	lines = LogFile.open(log_file_path).tail_log do |line|
		line.match("=== Log Marked") || line.match("=== Daemon Exception Backtrace")
	end
	
	output.puts lines
end