seamusabshere-daemon-spawn 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,16 @@
1
+ Autotest.add_hook(:initialize) do |at|
2
+ at.clear_mappings
3
+
4
+ at.add_mapping(/.*flymake/) do |f, _|
5
+ []
6
+ end
7
+
8
+ at.add_mapping(%r[lib/daemon-spawn.rb]) do |f, _|
9
+ at.files_matching /^test\/.*_test\.rb$/
10
+ end
11
+
12
+ at.add_mapping(/^test\/.*_test\.rb$/) do |filename, _|
13
+ filename
14
+ end
15
+
16
+ end
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ doc
2
+ pkg
data/History.txt ADDED
@@ -0,0 +1,20 @@
1
+ === 0.3.0 / 2010-04-18
2
+
3
+ * Typo fix and internal refactoring patches from Emmanuel Gomez
4
+ * Added multi-process spawning and management (inspired by Jontathan Tropper's
5
+ patches)
6
+ * Added LSB-compliance patches from Woody Peterson
7
+ * Added some actual test-coverage :-P
8
+ * Moved examples from "examples" directory to "test/servers"
9
+
10
+ === 0.2.0 / 2009-04-22
11
+
12
+ * Allow specification of args instead of ARGV so that scripts can
13
+ handle command line parsing and validation prior to spawning.
14
+
15
+ === 0.1.0 / 2009-01-26
16
+
17
+ * 1 major enhancement
18
+
19
+ * Happy Birthday!
20
+
data/Manifest.txt ADDED
@@ -0,0 +1,9 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/daemon_spawn.rb
6
+ test/daemon_spawn_test.rb
7
+ test/multi_daemon_spawn_test.rb
8
+ test/servers/echo_server.rb
9
+ test/servers/simple_server.rb
data/README.txt ADDED
@@ -0,0 +1,107 @@
1
+ = daemon-spawn
2
+
3
+ * http://github.com/alexvollmer/daemon-spawn
4
+
5
+ == DESCRIPTION:
6
+
7
+ Daemon launching and management made dead simple.
8
+
9
+ With daemon-spawn you can start, stop and restart processes that run
10
+ in the background. Processed are tracked by a simple PID file written
11
+ to disk.
12
+
13
+ In addition, you can choose to either execute ruby in your daemonized
14
+ process or 'exec' another process altogether (handy for wrapping other
15
+ services).
16
+
17
+ == SYNOPSIS:
18
+
19
+ === WRITING A DAEMON:
20
+
21
+ To create a new spawner, write a class that extends <tt>DaemonSpawn::Base</tt>
22
+ and provides +start+ and +stop+ methods. For example:
23
+
24
+ class MyServer < DaemonSpawn::Base
25
+
26
+ def start(args)
27
+ # process command-line args
28
+ # start your bad self
29
+ end
30
+
31
+ def stop
32
+ # stop your bad self
33
+ end
34
+ end
35
+
36
+ MyServer.spawn!(:log_file => '/var/log/echo_server.log',
37
+ :pid_file => '/var/run/echo_server.pid',
38
+ :sync_log => true,
39
+ :working_dir => File.dirname(__FILE__))
40
+
41
+ If you need command-line parameters, any arguments passed after one of
42
+ the commands (start, stop, status or restart) will be passed to the
43
+ +start+ method.
44
+
45
+ The <tt>spawn!</tt> method takes a hash of symbolized keys. At a minimum you
46
+ _must_ specify the <tt>:working_dir</tt> option. You can also override
47
+ the default locations for the log and PID files.
48
+
49
+ If you pass a <tt>:processes</tt> option to the <tt>spawn!</tt>,
50
+ daemon spawn will start that number of processes.
51
+
52
+ See the <tt>test/servers</tt> directory for working examples.
53
+
54
+ === RUNNING A DAEMON:
55
+
56
+ Let's say that you have the example script listed above in
57
+ <tt>bin/my_server</tt>. Here are the commands for starting, querying
58
+ the status, restarting and stopping the daemon:
59
+
60
+ bin/my_server start
61
+ bin/my_server status
62
+ bin/my_server restart
63
+ bin/my_server stop
64
+
65
+ Note that if any additional arguments are passed to either
66
+ <tt>start</tt> or <tt>restart</tt> those will be passed to the +start+
67
+ method of an instance of your daemon class.
68
+
69
+
70
+ == REQUIREMENTS:
71
+
72
+ None!
73
+
74
+ == CONTRIBUTIONS:
75
+
76
+ Feel free to fork this project and send me pull requests with any
77
+ changes that you have. Please note that I won't accept any patches
78
+ with significant formatting changes or ones without tests.
79
+
80
+ == INSTALL:
81
+
82
+ * sudo gem install daemon-spawn
83
+
84
+ == LICENSE:
85
+
86
+ (The MIT License)
87
+
88
+ Copyright (c) 2009 Evri, Inc.
89
+
90
+ Permission is hereby granted, free of charge, to any person obtaining
91
+ a copy of this software and associated documentation files (the
92
+ 'Software'), to deal in the Software without restriction, including
93
+ without limitation the rights to use, copy, modify, merge, publish,
94
+ distribute, sublicense, and/or sell copies of the Software, and to
95
+ permit persons to whom the Software is furnished to do so, subject to
96
+ the following conditions:
97
+
98
+ The above copyright notice and this permission notice shall be
99
+ included in all copies or substantial portions of the Software.
100
+
101
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
102
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
103
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
104
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
105
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
106
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
107
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # -*- ruby -*-
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "seamusabshere-daemon-spawn"
7
+ gemspec.summary = "A simple, flexible daemon management library. (re-released by Seamus Abshere)"
8
+ gemspec.description = %{gem 0.3.0 re-release... originally at http://github.com/alexvollmer/daemon-spawn}
9
+ gemspec.email = "seamus@abshere.net"
10
+ gemspec.homepage = "http://github.com/seamusabshere/daemon-spawn"
11
+ gemspec.authors = ["Alex Vollmer"]
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts "Jeweler not available. Install it with: gem install jeweler"
16
+ end
17
+
18
+ # vim: syntax=Ruby
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.1
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{daemon-spawn}
5
+ s.version = "0.2.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Alex Vollmer"]
9
+ s.date = %q{2009-09-21}
10
+ s.description = %q{Daemon launching and management made dead simple.
11
+
12
+ With daemon-spawn you can start, stop and restart processes that run
13
+ in the background. Processed are tracked by a simple PID file written
14
+ to disk.
15
+
16
+ In addition, you can choose to either execute ruby in your daemonized
17
+ process or 'exec' another process altogether (handy for wrapping other
18
+ services).}
19
+ s.email = ["alex.vollmer@gmail.com"]
20
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
21
+ s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/daemon-spawn.rb", "test/test_daemon-spawn.rb", "examples/echo_server.rb"]
22
+ s.homepage = %q{http://github.com/alexvollmer/daemon-spawn}
23
+ s.rdoc_options = ["--main", "README.txt"]
24
+ s.require_paths = ["lib"]
25
+ s.rubyforge_project = %q{daemon-spawn}
26
+ s.rubygems_version = %q{1.3.5}
27
+ s.summary = %q{Daemon launching and management made dead simple}
28
+ s.test_files = ["test/test_daemon-spawn.rb"]
29
+
30
+ if s.respond_to? :specification_version then
31
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
32
+ s.specification_version = 3
33
+
34
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
35
+ s.add_development_dependency(%q<hoe>, [">= 2.3.3"])
36
+ else
37
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
38
+ end
39
+ else
40
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
41
+ end
42
+ end
@@ -0,0 +1,197 @@
1
+ require 'fileutils'
2
+
3
+ # Large portions of this were liberally stolen from the
4
+ # 'simple-daemon' project at http://simple-daemon.rubyforge.org/
5
+ module DaemonSpawn
6
+ VERSION = '0.3.0'
7
+
8
+ def self.usage(msg=nil) #:nodoc:
9
+ print "#{msg}, " if msg
10
+ puts "usage: #{$0} <command> [options]"
11
+ puts "Where <command> is one of start, stop, restart or status"
12
+ puts "[options] are additional options passed to the underlying process"
13
+ end
14
+
15
+ def self.start(daemon, args) #:nodoc:
16
+ if !File.writable?(File.dirname(daemon.log_file))
17
+ STDERR.puts "Unable to write log file to #{daemon.log_file}"
18
+ exit 1
19
+ end
20
+
21
+ if !File.writable?(File.dirname(daemon.pid_file))
22
+ STDERR.puts "Unable to write PID file to #{daemon.pid_file}"
23
+ exit 1
24
+ end
25
+
26
+ if daemon.alive? && daemon.singleton
27
+ STDERR.puts "An instance of #{daemon.app_name} is already " +
28
+ "running (PID #{daemon.pid})"
29
+ exit 0
30
+ end
31
+
32
+ fork do
33
+ Process.setsid
34
+ exit if fork
35
+ open(daemon.pid_file, 'w') { |f| f << Process.pid }
36
+ Dir.chdir daemon.working_dir
37
+ File.umask 0000
38
+ log = File.new(daemon.log_file, "a")
39
+ log.sync = daemon.sync_log
40
+ STDIN.reopen "/dev/null"
41
+ STDOUT.reopen log
42
+ STDERR.reopen STDOUT
43
+ trap("TERM") {daemon.stop; exit}
44
+ daemon.start(args)
45
+ end
46
+ puts "#{daemon.app_name} started."
47
+ end
48
+
49
+ def self.stop(daemon) #:nodoc:
50
+ if pid = daemon.pid
51
+ FileUtils.rm(daemon.pid_file)
52
+ Process.kill("TERM", pid)
53
+ begin
54
+ Process.wait(pid)
55
+ rescue Errno::ECHILD
56
+ end
57
+ else
58
+ puts "PID file not found. Is the daemon started?"
59
+ end
60
+ rescue Errno::ESRCH
61
+ puts "PID file found, but process was not running. The daemon may have died."
62
+ end
63
+
64
+ def self.status(daemon) #:nodoc:
65
+ puts "#{daemon.app_name} is #{daemon.alive? ? "" : "NOT "}running (PID #{daemon.pid})"
66
+ end
67
+
68
+ class Base
69
+ attr_accessor :log_file, :pid_file, :sync_log, :working_dir, :app_name, :singleton, :index
70
+
71
+ def initialize(opts = {})
72
+ raise 'You must specify a :working_dir' unless opts[:working_dir]
73
+ self.working_dir = opts[:working_dir]
74
+ self.app_name = opts[:application] || classname
75
+ self.pid_file = opts[:pid_file] || File.join(working_dir, 'tmp', 'pids', app_name + extension)
76
+ self.log_file = opts[:log_file] || File.join(working_dir, 'logs', app_name + '.log')
77
+ self.index = opts[:index] || 0
78
+ if self.index > 0
79
+ self.pid_file += ".#{self.index}"
80
+ self.log_file += ".#{self.index}"
81
+ end
82
+ self.sync_log = opts[:sync_log]
83
+ self.singleton = opts[:singleton] || false
84
+ end
85
+
86
+ def classname #:nodoc:
87
+ self.class.to_s.split('::').last
88
+ end
89
+
90
+ # Provide your implementation. These are provided as a reminder
91
+ # only and will raise an error if invoked. When started, this
92
+ # method will be invoked with the remaining command-line arguments.
93
+ def start(args)
94
+ raise "You must implement a 'start' method in your class!"
95
+ end
96
+
97
+ # Provide your implementation. These are provided as a reminder
98
+ # only and will raise an error if invoked.
99
+ def stop
100
+ raise "You must implement a 'stop' method in your class!"
101
+ end
102
+
103
+ def alive? #:nodoc:
104
+ if File.file?(self.pid_file)
105
+ begin
106
+ Process.kill(0, self.pid)
107
+ rescue Errno::ESRCH, ::Exception
108
+ false
109
+ end
110
+ else
111
+ false
112
+ end
113
+ end
114
+
115
+ def pid #:nodoc:
116
+ IO.read(self.pid_file).to_i rescue nil
117
+ end
118
+
119
+ def self.build(options)
120
+ count = options.delete(:processes) || 1
121
+ daemons = []
122
+ count.times do |index|
123
+ daemons << new(options.merge(:index => index))
124
+ end
125
+ daemons
126
+ end
127
+
128
+ def self.find(options)
129
+ pid_file = new(options).pid_file
130
+ basename = File.basename(pid_file).split('.').first
131
+ pid_files = Dir.glob(File.join(File.dirname(pid_file), "#{basename}.*pid*"))
132
+ pid_files.map { |f| new(options.merge(:pid_file => f)) }
133
+ end
134
+
135
+ # Invoke this method to process command-line args and dispatch
136
+ # appropriately. Valid options include the following _symbols_:
137
+ # - <tt>:working_dir</tt> -- the working directory (required)
138
+ # - <tt>:log_file</tt> -- path to the log file
139
+ # - <tt>:pid_file</tt> -- path to the pid file
140
+ # - <tt>:sync_log</tt> -- indicate whether or not to sync log IO
141
+ # - <tt>:singleton</tt> -- If set to true, only one instance is
142
+ # allowed to start
143
+ # args must begin with 'start', 'stop', 'status', or 'restart'.
144
+ # The first token will be removed and any remaining arguments
145
+ # passed to the daemon's start method.
146
+ def self.spawn!(opts = {}, args = ARGV)
147
+ case args.any? and command = args.shift
148
+ when 'start', 'stop', 'status', 'restart'
149
+ send(command, opts, args)
150
+ when '-h', '--help', 'help'
151
+ DaemonSpawn.usage
152
+ exit
153
+ else
154
+ DaemonSpawn.usage "Invalid command"
155
+ exit 1
156
+ end
157
+ end
158
+
159
+ def self.start(opts, args)
160
+ daemons = find(opts)
161
+ if daemons.empty?
162
+ daemons = build(opts)
163
+ daemons.map { |d| DaemonSpawn.start(d, args) }
164
+ else
165
+ puts "Daemons already started! PIDS: #{daemons.map {|d| d.pid}.join(', ')}"
166
+ exit 1
167
+ end
168
+ end
169
+
170
+ def self.stop(opts, args)
171
+ daemons = find(opts)
172
+ if daemons.empty?
173
+ puts "No PID files found. Is the daemon started?"
174
+ exit 1
175
+ else
176
+ daemons.each { |d| DaemonSpawn.stop(d) }
177
+ end
178
+ end
179
+
180
+ def self.status(opts, args)
181
+ daemons = find(opts)
182
+ if daemons.empty?
183
+ puts 'No PIDs found'
184
+ else
185
+ daemons.each { |d| DaemonSpawn.status(d) }
186
+ end
187
+ end
188
+
189
+ def self.restart(opts, args)
190
+ daemons = find(opts)
191
+ daemons.map do |daemon|
192
+ DaemonSpawn.stop(daemon)
193
+ DaemonSpawn.start(daemon, args)
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,102 @@
1
+ require "socket"
2
+ require "test/unit"
3
+
4
+ class DaemonSpawnTest < Test::Unit::TestCase
5
+
6
+ SERVERS = File.join(File.dirname(__FILE__), "servers")
7
+
8
+ def with_socket
9
+ socket = TCPSocket.new('localhost', 5150)
10
+ socket.setsockopt(Socket::SOL_SOCKET,
11
+ Socket::SO_RCVTIMEO,
12
+ [1, 0].pack("l_2"))
13
+
14
+ begin
15
+ yield(socket) if block_given?
16
+ ensure
17
+ socket.close
18
+ end
19
+ end
20
+
21
+ def echo_server(*args)
22
+ `./echo_server.rb #{args.join(' ')}`
23
+ end
24
+
25
+ def while_running
26
+ Dir.chdir(SERVERS) do
27
+ `./echo_server.rb stop`
28
+ assert_match(/EchoServer started./, `./echo_server.rb start 5150`)
29
+ sleep 1
30
+ begin
31
+ with_socket
32
+ ensure
33
+ assert_match(//, `./echo_server.rb stop`)
34
+ assert_raises(Errno::ECONNREFUSED) { TCPSocket.new('localhost', 5150) }
35
+ end
36
+ end
37
+ end
38
+
39
+ def test_daemon_running
40
+ while_running do |socket|
41
+ socket << "foobar\n"
42
+ assert_equal "foobar\n", socket.readline
43
+ end
44
+ end
45
+
46
+ def test_status_running
47
+ while_running do |socket|
48
+ assert_match(/EchoServer is running/, `./echo_server.rb status`)
49
+ end
50
+ end
51
+
52
+ def test_status_not_running
53
+ Dir.chdir(SERVERS) do
54
+ assert_match(/No PIDs found/, `./echo_server.rb status`)
55
+ end
56
+ end
57
+
58
+ def test_start_after_started
59
+ while_running do
60
+ pid = echo_server("status").match(/PID (\d+)/)[1]
61
+ assert_match(/Daemons already started! PIDS: #{pid}/,
62
+ echo_server("start"))
63
+ end
64
+ end
65
+
66
+ def test_stop_after_stopped
67
+ Dir.chdir(SERVERS) do
68
+ assert_match("No PID files found. Is the daemon started?",
69
+ `./echo_server.rb stop`)
70
+ end
71
+ end
72
+
73
+ def test_restart_after_stopped
74
+ Dir.chdir(SERVERS) do
75
+ assert_match(/EchoServer started/, `./echo_server.rb restart 5150`)
76
+ assert_equal(0, $?.exitstatus)
77
+ sleep 1
78
+ with_socket do |socket|
79
+ socket << "foobar\n"
80
+ assert_equal "foobar\n", socket.readline
81
+ end
82
+ end
83
+ end
84
+
85
+ def test_restart_after_started
86
+ Dir.chdir(SERVERS) do
87
+ assert_match(/EchoServer started/, `./echo_server.rb start 5150`)
88
+ assert_equal(0, $?.exitstatus)
89
+ sleep 1
90
+
91
+ assert_match(/EchoServer started/, `./echo_server.rb restart 5150`)
92
+ assert_equal(0, $?.exitstatus)
93
+ sleep 1
94
+
95
+ with_socket do |socket|
96
+ socket << "foobar\n"
97
+ assert_equal "foobar\n", socket.readline
98
+ end
99
+ end
100
+ end
101
+
102
+ end
@@ -0,0 +1,111 @@
1
+ require "test/unit"
2
+ require "tempfile"
3
+
4
+ class MultiDaemonSpawnTest < Test::Unit::TestCase
5
+
6
+ SERVERS = File.join(File.dirname(__FILE__), "servers")
7
+
8
+ def setup
9
+ @tmpfile = Tempfile.new("multi_daemon_spawn_test")
10
+ end
11
+
12
+ def tear_down
13
+ @tmpfile.delete
14
+ end
15
+
16
+ def simple_server(*args)
17
+ `./simple_server.rb #{args.join(" ")}`
18
+ end
19
+
20
+ def current_pids
21
+ regexp = /SimpleServer is running \(PID (\d+)\)/
22
+ pids = simple_server("status").split("\n").map do |line|
23
+ if m = regexp.match(line)
24
+ m[1]
25
+ else
26
+ nil
27
+ end
28
+ end.compact
29
+ end
30
+
31
+ def while_running
32
+ Dir.chdir(SERVERS) do
33
+ simple_server "stop"
34
+ simple_server "start", @tmpfile.path
35
+ sleep 1
36
+ begin
37
+ yield if block_given?
38
+ ensure
39
+ simple_server "stop"
40
+ end
41
+ end
42
+ end
43
+
44
+ def test_start_multiple
45
+ while_running do
46
+ lines = open(@tmpfile.path).readlines
47
+ assert_equal 2, lines.size
48
+ assert lines.member?("SimpleServer (0) started\n")
49
+ assert lines.member?("SimpleServer (1) started\n")
50
+ end
51
+ end
52
+
53
+ def test_status_multiple
54
+ while_running do
55
+ lines = simple_server("status").split("\n")
56
+ lines.each do |line|
57
+ assert_match /SimpleServer is running/, line
58
+ end
59
+ end
60
+ end
61
+
62
+ def test_stop_multiple
63
+ while_running
64
+ Dir.chdir(SERVERS) do
65
+ assert_match /No PIDs found/, simple_server("status")
66
+ end
67
+ end
68
+
69
+ def test_restart_multiple
70
+ while_running do
71
+ pids = current_pids
72
+ simple_server "restart"
73
+ new_pids = current_pids
74
+ assert_not_equal pids.sort, new_pids.sort
75
+ end
76
+ end
77
+
78
+ def test_status_with_one_dead_process
79
+ while_running do
80
+ pids = current_pids
81
+ Process.kill(9, pids[0].to_i)
82
+
83
+ lines = simple_server("status").split("\n")
84
+ assert_equal 2, lines.size
85
+ assert lines.member?("SimpleServer is NOT running (PID #{pids[0]})")
86
+ assert lines.member?("SimpleServer is running (PID #{pids[1]})")
87
+ end
88
+ end
89
+
90
+ def test_restart_with_one_dead_process
91
+ while_running do
92
+ pids = current_pids
93
+ Process.kill(9, pids[0].to_i)
94
+
95
+ lines = simple_server("restart").split("\n")
96
+ assert lines.member?("PID file found, but process was not running. The daemon may have died."), lines.inspect
97
+ assert_equal 2, lines.select { |l| l == "SimpleServer started." }.size
98
+
99
+ new_pids = current_pids
100
+ assert_not_equal new_pids, pids
101
+ end
102
+ end
103
+
104
+ def test_start_after_started
105
+ while_running do
106
+ pids = current_pids
107
+ assert_match(/Daemons already started! PIDS: #{pids.join(', ')}/,
108
+ simple_server("start"))
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "..", "lib"))
4
+
5
+ require "daemon_spawn"
6
+ require "socket"
7
+
8
+ # An echo server using daemon-spawn. It starts up local TCP server
9
+ # socket and repeats each line it receives on the connection. To fire
10
+ # it up run:
11
+ # ./echo_server.rb start 12345
12
+ # Then connect to it using telnet to test it:
13
+ # telnet localhost 12345
14
+ # > howdy!
15
+ # howdy!
16
+ # to shut the daemon down, go back to the command-line and run:
17
+ # ./echo_server.rb stop
18
+ class EchoServer < DaemonSpawn::Base
19
+
20
+ attr_accessor :server_socket
21
+
22
+ def start(args)
23
+ port = args.empty? ? 0 : args.first.to_i
24
+ self.server_socket = TCPServer.new('127.0.0.1', port)
25
+ self.server_socket.setsockopt(Socket::SOL_SOCKET,
26
+ Socket::SO_REUSEADDR,
27
+ true)
28
+ port = self.server_socket.addr[1]
29
+ puts "EchoServer started on port #{port}"
30
+ loop do
31
+ begin
32
+ client = self.server_socket.accept
33
+ puts "Got a connection from #{client}"
34
+ while str = client.gets
35
+ client.write(str)
36
+ puts "Echoed '#{str}' to #{client}"
37
+ end
38
+ rescue Errno::ECONNRESET => e
39
+ STDERR.puts "Client reset connection"
40
+ end
41
+ end
42
+ end
43
+
44
+ def stop
45
+ puts "Stopping EchoServer..."
46
+ self.server_socket.close if self.server_socket
47
+ end
48
+ end
49
+
50
+ EchoServer.spawn!(:working_dir => File.join(File.dirname(__FILE__), '..', '..'),
51
+ :log_file => '/tmp/echo_server.log',
52
+ :pid_file => '/tmp/echo_server.pid',
53
+ :sync_log => true,
54
+ :singleton => true)
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "..", "lib"))
4
+
5
+ require "daemon_spawn"
6
+
7
+ class SimpleServer < DaemonSpawn::Base
8
+
9
+ attr_accessor :outfile
10
+
11
+ def start(args)
12
+ abort "USAGE: phrase_server.rb LOGFILE" if args.empty?
13
+ @outfile = args.first
14
+ self.puts "SimpleServer (#{self.index}) started"
15
+ while true # keep running like a real daemon
16
+ sleep 5
17
+ end
18
+ end
19
+
20
+ def puts(str)
21
+ open(@outfile, "a") { |f| f.puts str }
22
+ end
23
+
24
+ def stop
25
+ self.puts "SimpleServer (#{self.index}) stopped"
26
+ end
27
+
28
+ end
29
+
30
+ SimpleServer.spawn!(:working_dir => File.join(File.dirname(__FILE__), '..', '..'),
31
+ :log_file => '/tmp/simple_server.log',
32
+ :pid_file => '/tmp/simple_server.pid',
33
+ :sync_log => true,
34
+ :processes => 2)
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seamusabshere-daemon-spawn
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 1
9
+ version: 0.2.1
10
+ platform: ruby
11
+ authors:
12
+ - Alex Vollmer
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-20 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: gem 0.3.0 re-release... originally at http://github.com/alexvollmer/daemon-spawn
22
+ email: seamus@abshere.net
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.txt
29
+ files:
30
+ - .autotest
31
+ - .gitignore
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - Rakefile
36
+ - VERSION
37
+ - daemon-spawn.gemspec
38
+ - lib/daemon_spawn.rb
39
+ - test/daemon_spawn_test.rb
40
+ - test/multi_daemon_spawn_test.rb
41
+ - test/servers/echo_server.rb
42
+ - test/servers/simple_server.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/seamusabshere/daemon-spawn
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.6
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: A simple, flexible daemon management library. (re-released by Seamus Abshere)
73
+ test_files:
74
+ - test/daemon_spawn_test.rb
75
+ - test/multi_daemon_spawn_test.rb
76
+ - test/servers/echo_server.rb
77
+ - test/servers/simple_server.rb